Friday, November 23, 2007

A Major Milestone for Tally-Ho: Arbitrary HTML Pages

Tonight I created the first localized, arbitrary HTML page in Tally-Ho. I don't have all of the corner cases handled yet, but I was able to go to the creation page, choose a Locale, give an arbitrary "path", filename, title and content, save the page and then view the page with a nice URL that makes it look like a static page.

The whole mess integrates directly into the Tally-Ho BinaryResourceService locator/localizer system, just as the existing Wicket integration via the BinaryResourceStreamLocator does now, so it automatically takes advantage of localization and caching.

One of the more cumbersome challenges in this effort was getting a nice URL. Wicket has many URL coding strategies for Bookmarkable pages; I use IndexedParamUrlCodingStrategy quite a bit. But IndexedParamUrlCodingStrategy wasn't going to work in this case. It takes each element of a path and associates it with an index number. What I needed was the path itself as a parameter, not chopped up and indexed.

It turns out that writing one of these coding strategies from scratch for Wicket is difficult if you don't know what you're doing (like me), and the Javadoc for the various classes involved is sadly a bit lacking in direction. So I took a different approach: I stole a bunch of code from IndexedParamUrlCodingStrategy and modified it to fit my needs. Behold, UriPathUrlCodingStrategy (with comments snipped for space... they're in CVS, though, and rest assured they credit Igor for writing IndexedParamUrlCodingStrategy):

package net.spatula.tally_ho.wicket;

import java.util.Map;

import wicket.Application;
import wicket.PageMap;
import wicket.PageParameters;
import wicket.WicketRuntimeException;
import wicket.protocol.http.request.WebRequestCodingStrategy;
import wicket.settings.IRequestCycleSettings;
import wicket.util.string.AppendingStringBuffer;
import wicket.util.value.ValueMap;

public class UriPathUrlCodingStrategy extends BookmarkablePageRequestTargetUrlCodingStrategy {

public UriPathUrlCodingStrategy(String mountPath, Class bookmarkablePageClass) {
super(mountPath, bookmarkablePageClass, PageMap.DEFAULT_NAME);

public UriPathUrlCodingStrategy(String mountPath, Class bookmarkablePageClass, String pageMapName) {
super(mountPath, bookmarkablePageClass, pageMapName);

protected void appendParameters(AppendingStringBuffer url, Map parameters) {
if (parameters.containsKey("uri")) {
String[] pathParts = ((String) parameters.get("uri")).split("/+");
for (String string : pathParts) {
if (string == null || "".equals(string)) {
try {
Application app = Application.get();
IRequestCycleSettings settings = app.getRequestCycleSettings();
url.append("/").append(, settings.getResponseRequestEncoding()));
} catch (UnsupportedEncodingException e) {
throw new WicketRuntimeException(e);

String pageMap = (String) parameters.get(WebRequestCodingStrategy.PAGEMAP);
if (pageMap != null) {


protected ValueMap decodeParameters(String urlFragment, Map urlParameters) {
PageParameters params = new PageParameters();
if (urlFragment == null) {
return params;
if (urlFragment.startsWith("/")) {
urlFragment = urlFragment.substring(1);

String[] parts = urlFragment.split("/");
StringBuilder builder = new StringBuilder();
for (int i = 0; i < parts.length; i++) {
if (WebRequestCodingStrategy.PAGEMAP.equals(parts[i])) {
params.put(WebRequestCodingStrategy.PAGEMAP, parts[i]);
} else {
params.put("uri", builder.toString());
return params;


The next steps will be update capability for the HTML pages and then an attachment selector/uploader tool to handle the association of other resources to the HTML page.

This will be a giant leap forward for Tally-Ho and allow for the conversion of dozens of old pages to the new system.

Labels: , ,

I am so bookmarking you. I think we've been leading parallel lives for the last six months.

I, too, am struggling with Wicket+JPA+Tomcat+Eclipse

Though I just followed N8han's advice and switched to Jetty, one JVM per site. Real process isolation RULES and I don't care about the overhead ;-)

Post a Comment

<< Home

This page is powered by Blogger. Isn't yours?

Subscribe to Posts [Atom]