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!