During request handling, Wicket manages page instances through interface @org.apache.wicket.request.handler.IPageProvider@. This interface creates a new page instance or loads a previously serialized page instance if we provide the corrisponding page id. @IPageProvider@ delegates page creation and retrieval to interface @org.apache.wicket.request.mapper.IPageSource@.
When page class is provided @IPageSource@ delegates page creation to interface @org.apache.wicket.IPageFactory@, while when page id is provided it uses interface @org.apache.wicket.page.IPageManager@ to load the previously serialized page.

The following workflow diagram summarizes the mechanism seen so far:

!page-storage.png!

h3. 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@.

h3. 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:

{code}
{
   sessionId: String,
   pageId : int,
   data : byte[]
}
{code}

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)@.

h3. 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.

h3. 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@.

h3. DebugDiskDataStore

Wicket provides an extension of @DiskDataStore@ that can be used to browse the content of the 'data' files created by @DiskDataStore@. This extension can be found in wicket-devutils.jar and needs to be enabled in the @init@-method of your application via 
{code}
 DebugDiskDataStore.register(this);
{code}
The debug information can be seen at http://host:port/context/wicket/internal/debug/diskDataStore

h3. 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:
{code}
MyApp#init()
{
   super.init();
 
   setPageManagerProvider(new DefaultPageManagerProvider(this)
   {
       protected IDataStore newDataStore()
       {
           return  new HttpSessionDataStore(getPageManagerContext(), new PageNumberEvictionStrategy(20));
       }
   }
}
{code}

h3. DebugBar

Further insights which can be valueable during debugging can be retrieved using the @org.apache.wicket.devutils.debugbar.DebugBar@ from wicket-devutils.jar. It's a panel which you simply add:

Java: 
{code}
add(new DebugBar("debug"));
{code}

HTML:
{code}
<span wicket:id="debug"/>
{code}
