Another hour of debugging revealed the problem...

The MarkupCache method loadMarkupAndWatchForChanges has code which shortcuts our custom cache key:

// get the location String
String locationString = markupResourceStream.locationAsString();
            if (locationString == null)
            {
// set the cache key as location string, because location string
                // couldn't be resolved.
                locationString = cacheKey;
            }

Since our child pages are loaded through wicket's default resource loading mechanism, a MarkupResourceStream instance is used.
The MarkupCache has a level of indirection:
cacheKey => locationString
locationString => cached markup

Since our child pages' markup resource stream have a location on disk, this effectively means wicket caches the actual content only once instead of per theme: all our custom cache keys point to the same location string.

The fix was easy: I created an IResourceStreamWrapper class, and let it wrap the MarkupResourceStream of child pages. This effectively makes them return a null location string, and thus the child pages are cached per theme.

Met vriendelijke groet,
Kind regards,

Bas Gooren

Op 3-10-2013 19:11, schreef Bas Gooren:
Sorry, I forgot to add that this is a wicket 1.5 app.

As a quick follow-up, after looking at the InheritedMarkupMarkupLoader, I see that it delegates loading of the parent (base page) markup to the MarkupFactory.

I think that means that our current setup should work, when it doesn't.

Met vriendelijke groet,
Kind regards,

Bas Gooren

Op 3-10-2013 18:59, schreef Bas Gooren:
Hi *,

We built an app which has a base page, and several child pages which inherit from the base page. The app is themeable, and one of the requirements of the app is/was that these themes should be manageable.
This means we have a set of themes which can be changed on-the-fly.

To add flexibility to our app, a theme can override the html of the base page. To handle the custom html, our base page implements IMarkupResourceStreamProvider and IMarkupCacheKeyProvider.

Every user of the app can select a theme, so the theme is determined per request.

The cache key is generated based on the theme id and the container class:

@Override
public String getCacheKey( MarkupContainer container, Class< ? > containerClass )
    {
        final Theme theme = getWebsite().getTheme();
return "Theme#" + theme.getId() + "-" + containerClass.getName();
    }

The markup resource stream is only "overriden" for the base page:

@Override
public IResourceStream getMarkupResourceStream( MarkupContainer container, Class< ? > containerClass )
    {
        final Theme theme = getWebsite().getTheme();

        if( containerClass.equals( WebsiteLayout.class ) )
        {
            String markup = theme.getMarkup();
            return new StringResourceStream( markup, "text/html" );
        }

return defaultResourceStreamProvider.getMarkupResourceStream( container, containerClass );
    }

(where defaultResourceStreamProvider is a DefaultMarkupResourceStreamProvider instance).

The problem we are facing is that when the user switches to a different theme, they keep seeing the html code of the previously selected theme. Debugging shows that when the theme is changed:
- getCacheKey is hit for both the child page and the base page
- getMarkupResourceStream is hit for both the child page and the base page

I think it could be due to the way wicket's DefaultMarkupResourceStreamProvider handles inheritance: maybe it (too) caches the base page markup?

Can anyone help with this? How do we properly cache dynamic html for a base page which is used by several (static) child pages?

Thanks!




Reply via email to