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.

12 comments:

  1. Anonymous8:05 PM

    good work!

    ReplyDelete
  2. That's really great! Good work.
    But I hope URLs are still configurable like Tap4 where you can add some strings to the URL (Not only the primary key).
    Example case: an URL that displays the information about a house. It's efficient for search engines to have, the name of the house, the country, the city and the type in the URL, it makes those keywords more relevant. For example: "http://localhost/Appartement/France/Paris/Luxurious/45"

    Another concern for URLs are datasqueezers, these are not always so practical (they are not thread safe). For example beans that are just plain data holder for database query parameters (ex: HouseSeachQueryParam that holds the houseName, houseLocation, houseCategory, CurrentPage, MaxResultsPerPage)
    You don't want to keep these beans in the session for every visitor on the site (if you have more then 10000 visitor a day, it takes a lot of RAM), and you want the result of a query to be bookmarkable by the visitor. It will be nice to have a way for a service to encode Simple beans property inside the url.
    Ex http://localhost/House/Search?Bean=HouseSearchQueryParam.b&b.houseName=Corbusier&b.houseCategory=Luxurious&b.houseLocation=Paris&b.currentPage=2&b.maxResultsPerPage=10

    I think this is a must have feature if you don't want to store query params in the session. The URL scheme can be different, but the idea is that a bean can be introspected and each property squeezed, instead of squeezing the whole bean. And making a special dataSqueezer for each bean is quite hard.

    I hope you might have an idea for that!

    Thanks

    Numa

    ReplyDelete
  3. Anonymous3:47 AM

    Howard, you're a bloody genius! I just can't wait for this barrel of goodness, T5. I just hope that migrating won't be a big pain because I'll probably be the first in line to try.

    ReplyDelete
  4. Anonymous9:44 PM

    Great work!

    ReplyDelete
  5. Nice.

    Have you considered dumping the J2EE stack in favour of something altogether
    simple
    r, more maleable and more scalable?

    ReplyDelete
  6. Actually, very little of the internal design of Tapestry is directly linked to the Servlet API. This is primarily so that it is possible to use Tapestry with Portlets, and eventually to support alternate uses such as offline rendering. Assuming the Simple framework APIs are remotely similar to Servlet APIs, it should not be too difficult to bridge them together. But that's not a priority for me.

    ReplyDelete
  7. Anonymous5:01 AM

    Hi anonymous,

    Stop calling Howard a genius because I don't think he deserves that title yet. What he's doing now is just hacking and refactoring existing ideas. If his idea was totally new and innovative, then I'll agree with you but, IMHO that's not the case. And I believe Howard himself agrees with me on this point.

    ReplyDelete
  8. Nope, I'm a genius :-)

    In all honesty, I'm always a little put off by some of the gushing praise that shows up (even if it is quite gratifying at some level). However, Tapestry 5 represents much, much more than the sum of its parts, and many of its parts are quite impressive in their own right.

    I've long stated that Tapestry 4 (and all the prior versions leading up to it), was the "prototype that escaped the lab". Tapestry 5 is the Real Deal, a new vision of how to build and structure Java web applications, with tremendous innovations in the way a framework and end-user code work together, without sacrificing performance.

    I'm expecting to finish up my first pass at a simple BeanEditor component and then we'll push for an initial preview release.

    ReplyDelete
  9. Ouch ... the thing about case-insensitivity is that hardly anything ELSE in the chain is case-insensitive. Caches all the way along are going to treat differently-cased URLs differently, for example.

    Now I think case-insensitivity is actually a good thing, but it seems to me that it's better done as a rewrite by whatever server is front-ending the app than by folding case within the framework itself.

    Convince me otherwise?

    ReplyDelete
  10. Tapestry 5 URLs are much shorter than the equivalent in Tapestry 4, espcially for page render URLs, the kind that users will see in the browser, bookmark, copy and paste, or manually type.

    The framework itself needs to be prepared to handle a user munging the case when manually enterring a URL.

    This could be done with Apache mod_rewrite, or the equivalent, to intercept requests and canonicalize the case. However, I never like deferring such important configuration outside of Tapestry and the WAR, since it represents more work and confusion at deployment time (which is always a mess, for any web application). Letting Tapestry "be generous in what it accepts, and specific in what it produces" is the HTML/HTTP way.

    And the all-lower-case URLs just "look cool". That's actually an important marketting factor.

    ReplyDelete
  11. Caseless URLs are duplicate content in the eyes of Google and should be avoided....

    ReplyDelete
  12. @Toby:

    That might be the case if the URLs were all mixed case but part of the point of Tapestry is that these things happen consistently: rendered URLs are all lower case but if a user manually enters a URL with mixed case, it will still work.

    ReplyDelete

Please note that this is not a support forum for Tapestry. Requests for help will be deleted. Please subscribe to the Tapestry user mailing list if you are in need of support, or contact me directly for professional (for pay) support.

Spammers: Don't bother. I delete your comments and it's a waste of time for both of us. 垃圾邮件发送者:不要打扰。我删除您的评论和它的时间对我们双方的浪费