This page may be outdated! Please use the reference guide

Wicket 1.5 - Page storage

Introduction

This page describes the internals of Wicket page storages in version 1.5.

Involved classes

picture here

IPageProvider

org.apache.wicket.request.handler.IPageProvider's task is to return a page instance by page id or page class.
Default implementation provided by Wicket is org.apache.wicket.request.handler.PageProvider, which delegates page creation and retrieval to a IPageSource.

IPageSource

Default implementation of org.apache.wicket.request.mapper.IPageSource is org.apache.wicket.DefaultMapperContext.
When page class is provided then DefaultMapperContext delegates to IPageFactory. When page id is provided it will delegate to IPageManager to find the page.

IPageFactory

org.apache.wicket.IPageFactory creates pages.

IPageManager

org.apache.wicket.page.IPageManager's task is to manage which pages have been used in a request and store their last state in the backing stores, namely IPageStore.
The default implementation org.apache.wicket.page.PageStoreManager collects all stateful pages which have been used in the request cycle (more than one page can be used in a single request if for example setResponsePage() or RestartResponseException is used).
At the end of the request all collected page instances are being stored in the first level cache - http session. They are stored in http session attribute named "wicket:persistentPageManagerData-APPLICATION_NAME" and passed to the underlying IPageStore.
When the next http request comes IPageProvider will ask for page with specific id and PageStoreManager will look first in the http session and if no match is found then it will delegate to the IPageStore. At the end of the second request the http session based cache is being overwritten completely with the newly used page instances.

To setup another IPageManager implementation use org.apache.wicket.Application.setPageManagerProvider(IPageManagerProvider).
The custom IPageManager implementation may or may not use IPageStore/IDataStore.

IPageStore

org.apache.wicket.pageStore.IPageStore's role is to mediate the storing and loading of pages done by the underlying IDataStore.
The default implementation org.apache.wicket.pageStore.DefaultPageStore pre-processes the pages before passing them to IDataStore#storeData(String, int, byte[]) and to post-processes them after IDataStore#getData(String, int). The processing consists of transforming the page instance to org.apache.wicket.pageStore.DefaultPageStore.SerializedPage. This is a struct of:
{
sessionId: String,
pageId : int,
data : byte[]
}
i.e. this is the serialized page instance (data) plus additional information needed to be able to easily find it later (sessionId, pageId).

When a SerializedPage has to be stored DefaultPageStore stores it in a application scoped cache ({sessionId, pageId} -> SerializedPage) and additionally
gives it to the underlying IDataStore (#storeData(sessionId, pageId, data). The application scoped cache is used as second level cache. Getting a page from it is slower than the http session based cache in PageStoreManager because the page has to be deserialized, but is faster than the underlying IDataStore which stores the page bytes in some persistent store.

The size of the application scoped cache is configurable via org.apache.wicket.settings.IStoreSettings.setInmemoryCacheSize(int).

IDataStore

org.apache.wicket.pageStore.IDataStore is used to persist Wicket pages (as bytes) to a persistent store like e.g. files or databases.
The default implementation is org.apache.wicket.pageStore.DiskDataStore which as its name says stores the pages in files.
The location of the folder where the files are stored is configurable via org.apache.wicket.settings.IStoreSettings.setFileStoreFolder(File), by default the web container's work folder is used (ServletContext attribute 'javax.servlet.context.tempdir'). In this folder a sub-folder is created named 'applicationName-filestore'. This folder contains a sub-folder for each active http session. This session folder contains a single file named 'data' which contains the bytes for the pages. The size of this 'data' file is configurable via org.apache.wicket.settings.IStoreSettings.setMaxSizePerSession(Bytes). When this size is exceeded the newly stored files overwrite the oldest ones.

Additional information

AsynchronousDataStore

By default Wicket wraps DiskDataStore with org.apache.wicket.pageStore.AsynchronousDataStore. The role of AsynchronousDataStore is to detach the http worker thread from waiting for the write of the page bytes to the disk.
To disable it use: org.apache.wicket.settings.IStoreSettings.setAsynchronous(false).
AsynchronousDataStore can delay the storage of pages' bytes for at most org.apache.wicket.settings.IStoreSettings.setAsynchronousQueueCapacity(int) pages. If this capacity is exceeded then the page's bytes are written synchronously to the backing IDataStore.

DebugDiskDataStore

With Wicket 1.5-RC6 will be available an extension of DiskDataStore that can be used to browse the content of the 'data' files created by DiskDataStore.
This debug enabled DiskDataStore is automatically setup when wicket-devutils.jar is in the classpath.
The debug information can be seen at http://host:port/context/wicket/internal/debug/diskDataStore

HttpSessionDataStore

In some environments like Google AppEngine it is not allowed to write to the file system and thus DiskDataStore cannot be used. In this case org.apache.wicket.pageStore.memory.HttpSessionDataStore can be used as replacement. This implementation of IDataStore is not persistent and puts all the data in the http session.
Wicket comes with 2 default eviction strategies to keep the size of the http session reasonable:

  • org.apache.wicket.pageStore.memory.PageNumberEvictionStrategy - specifies how many pages can be hold
  • org.apache.wicket.pageStore.memory.MemorySizeEvictionStrategy - specifies the maximum amount of memory for pages per http session.

To configure it:

MyApp.java
MyApp#init()
{
   super.init();

   setPageManagerProvider(new DefaultPageManagerProvider() 
   {
       protected IDataStore newDataStore() 
       { 
           return  new HttpSessionDataStore(pageManagerContext, new PageNumberEvictionStrategy(20));
       }
   }
}

PageExpiredException

org.apache.wicket.protocol.http.PageExpiredException may be thrown by PageProvider when none of the underlying storages can find a page with specific id.
The reasons could be:

  • the page have never been stored
  • IStoreSettings.setMaxSizePerSession(Bytes) is not big enough and the page bytes were already overwritten
  • the http session has expired and thus all the data about it (including stored pages) is erased from all stores