Jakarta > Tapestry
Jakarta
 
Font size:      

Configuring Friendly URLs

Earlier versions of Tapestry have had a long-standing tradition of really ugly URLs. Because the framework generates the URLs and is also responsible for parsing and dispatching on them in later requests, it was not seen as an issue.

In fact, the ugly URLs do cause some problems:

Starting with 3.1, friendly URLs are integrated directly into framework (in 3.0 an ambitious, but more limited, patch was required).

Friendly URLs are divided into two aspects:

For example, the ugly URL /app?page=news/Thread&service=page may be converted into the friendly URL /news/Threads.html. In this case, the page=news/Thread query parameter becamethe news/Thread portion of the URL, and the service=page query parameter became the .html extension to the URL.

Understanding Tapestry URLs

To understand how to get friendly URLs, you must understand a little about what information Tapestry packs into URLs.

Every request to a Tapestry application is mapped to an engine service. An engine service is something like a servlet, embedded within Tapestry. The service query parameter is used to select an engine service by name. A number of services are provided with the framework, the most common of which are:

page
Activates and renders a specific page.
direct
Used with the DirectLink and Form components.
home
Default service used when the service parameter is not specified (such as when first accessing the application); activates and renders the Home page.

Each service is responsible for creating URLs with the correct query parameters. By default, the URL path is always /app and any additional information comes out of the query parameters. The most common parameters are:

page
The name of a page to activate.
service
The service responsible for the request.
component
The nested component id of a component.
sp
Stores service parameters passed in the URL (used by DirectLink).

This a typical URL might be /app?component=border.logout&page=news/Thread&service=direct. Yep, that's UGLY.

Enabling Friendly URLs

To use ordinary ugly URLs, Tapestry requires only a small amount of configuration in web.xml. Enabling friendly URLs requires adding more configuration to web.xml, and to your HiveMind module deployment descriptor.

Friendly URLs are controlled by ServiceEncoders. Getting Tapestry to output friendly URLs is a matter of plugging encoders into the correct pipeline ... this is all done using HiveMind.

page-service-encoder

The most common type of encoder is the page-service-encoder, which encodes the page and service parameters. In your hivemodule.xml:

<contribution configuration-id="tapestry.url.ServiceEncoders">
  <page-service-encoder id="page" extension="html" service="page"/>
</contribution>

This contribution to the tapestry.url.ServiceEncoders configuration point creates a ServiceEncoder that maps the .html extension (on the URL path) to the page service. The id attribute must be unique for all contributed encoders.

For Tapestry to recognize the URLs, you must inform the servlet container to send them to the Tapestry application servlet, by addining a mapping to web.xml:

<servlet-mapping>
  <servlet-name>myapp</servlet-name>
  <url-pattern>*.html</url-pattern>
</servlet-mapping>
Note
This means that even static HTML pages that are part of your web application will be treated as Tapestry pages; any incoming request that ends with .html will be routed into the Tapestry application. Page specifications are optional, so Tapestry will treat the HTML pages are if they were HTML page templates. If you want to allow ordinary static content, then you should use another extension such as ".page" or ".tap" (the choice is arbitrary).

extension-encoder

The extension-encoder isused to encode just the service query parameter. The output URL is the service name with a fixed extension (typically, ".svc"), i.e., /home.svc or /restart.svc.

In your hivemodule.xml:

<contribution configuration-id="tapestry.url.ServiceEncoders">
  <extension-encoder id="extension" extension="svc" after="*"/>
</contribution>

The use of the after attribute ensures that this encoder is always executed after any other encoders. Order is important!

For this example, another mapping is required in the web.xml:

<servlet-mapping>
  <servlet-name>myapp</servlet-name>
  <url-pattern>*.svc</url-pattern>
</servlet-mapping>