Did a lot of work this weekend on the Tapestry URL front. If you are familiar with Tapestry, you know that nobody likes the way the URLs are formatted. That's an issue, because you don't have control over it ... Tapestry is responsible for building the URLs (a very good thing) and does all the dispatching and so forth (again, very good thing). But Tapestry's butt ugly URLs are a problem for many.
- All URLs are built off a single servlet, typically
/app. This defeats J2EE declarative security, which is path based.
- The URLs are longish. For example,
There's a rhyme and a reason to all that, but its very much oriented around the code and not the users.
- The use of the slash ("/") character in the URLs is an impediment to breaking the application into modules (i.e., putting the admin pages into an "admin" folder).
- The emphasis on query parameters means that most of an application, after the home page, will be "off limits" to any kind of web spider, such as Google.
I spent a large portion of the last few days working on this, and I'm halfway there. Of course, you'd hardly know it ... if you download Tapestry from CVS and built it right now, you'd see that the URLs have gotten longer! That service query parameter has been broken up into several smaller variables: service, page, component and, where necessary, container. Some Tapestry engine services add others (for example, the asset service has a path query parameter).
That means that the example URL from before would look like:
The next step (the work not yet done) is more fun ... what if we converted the page query parameter into more path info, and the service into an extension? Then our URL is much friendlier:
If we map the .html extension to the home service, then a Tapestry page looks like a normal HTML page:
From a client web browser, that's a reference to a Tapestry page, even though it looks like just the page's HTML template. With this kind of mapping, you might not even use the PageLink component in your templates, just ordinary HTML links:
<a jwcid="@PageLink" page="misc/About">About</a>
Getting all of this to work for your own application will require:
- Adding path mappings to your web.xml:
<servlet-mapping> <servlet-name>app</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping>
- Adding configuration data (HiveMind contributions) to your application, to tell Tapestry about those mappings:
<map-extension extension="html" service-name="page"/>
Hopefully, I can get more of this going in the next couple of days (I have a long flight out to San Francisco this week).
Still, even with these improvements, the URLs aren't perfect. There's some dissatisfaction with bookmarking URLs with the external service; any extra data is encoded into the sp parameter, which has a prefixing system to identify the type of data. For example, "S" for string, "d" for double, "O" for serialized object.
Talking with Erik, I had the idea that we could simplify things by creating a service that bookmarked some set of page properties into the URL. So you might have a ShowAccount page, with an accountId property of type long. The accountId property gets converted into a string as part of the URL. Later, when the request is submitted, the accountId query parameter is converted back to a long and pluggined into the page's actionId property. The end result is a "pretty" URL:
This is much prettier than what you might accomplish in Tapestry 3.0 using the external service:
I think Erik wants to go further though ... he wants something like:
I think we can get there. I think we can allow one extension to map to different services (here, the extra query parameter hints that this is a bookmark service, not a page service, request). It's a matter of flexible interfaces and flexible HiveMind contributions.