You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@wicket.apache.org by Maxim Solodovnik <so...@gmail.com> on 2020/03/27 13:24:36 UTC

Re: [wicket] branch master updated: WICKET-6563 add CachingPageStore

Hello Sven,

Are there any changes for wicketstuff-datastore required?

On Fri, 27 Mar 2020 at 20:18, <sv...@apache.org> wrote:

> This is an automated email from the ASF dual-hosted git repository.
>
> svenmeier pushed a commit to branch master
> in repository https://gitbox.apache.org/repos/asf/wicket.git
>
>
> The following commit(s) were added to refs/heads/master by this push:
>      new 8df3528  WICKET-6563 add CachingPageStore
> 8df3528 is described below
>
> commit 8df3528dc44a08b7d375c20e764a3664cd6a5f30
> Author: Sven Meier <sv...@apache.org>
> AuthorDate: Fri Mar 27 10:13:13 2020 +0100
>
>     WICKET-6563 add CachingPageStore
> ---
>  .../apache/wicket/DefaultPageManagerProvider.java  |   9 +-
>  .../apache/wicket/pageStore/CachingPageStore.java  | 109
> +++++++++++++++++++++
>  .../wicket/pageStore/InSessionPageStore.java       |  82 ++++++----------
>  .../wicket/DefaultPageManagerProviderTest.java     |   6 +-
>  .../core/request/mapper/TestMapperContext.java     |   7 +-
>  .../wicket/page/PersistentPageManagerTest.java     |   2 +-
>  .../wicket/pageStore/InSessionPageStoreTest.java   |  18 +++-
>  .../wicket/versioning/PageVersioningTest.java      |   4 +-
>  8 files changed, 174 insertions(+), 63 deletions(-)
>
> diff --git
> a/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
> b/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
> index e128266..540b1b3 100644
> ---
> a/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
> +++
> b/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
> @@ -21,6 +21,7 @@ import java.io.File;
>  import org.apache.wicket.page.IPageManager;
>  import org.apache.wicket.page.PageManager;
>  import org.apache.wicket.pageStore.AsynchronousPageStore;
> +import org.apache.wicket.pageStore.CachingPageStore;
>  import org.apache.wicket.pageStore.CryptingPageStore;
>  import org.apache.wicket.pageStore.DiskPageStore;
>  import org.apache.wicket.pageStore.FilePageStore;
> @@ -103,7 +104,7 @@ public class DefaultPageManagerProvider implements
> IPageManagerProvider
>
>                 store = newAsynchronousStore(store);
>
> -               store = newSessionStore(store);
> +               store = newCachingStore(store);
>
>                 store = newRequestStore(store);
>
> @@ -125,7 +126,7 @@ public class DefaultPageManagerProvider implements
> IPageManagerProvider
>         }
>
>         /**
> -        * Cache pages in the request until it is finished.
> +        * Keep pages in the request until it is finished.
>          *
>          * @see RequestPageStore
>          */
> @@ -139,9 +140,9 @@ public class DefaultPageManagerProvider implements
> IPageManagerProvider
>          *
>          * @see InSessionPageStore
>          */
> -       protected IPageStore newSessionStore(IPageStore pageStore)
> +       protected IPageStore newCachingStore(IPageStore pageStore)
>         {
> -               return new InSessionPageStore(pageStore, 1,
> getSerializer());
> +               return new CachingPageStore(pageStore, new
> InSessionPageStore(1, getSerializer()));
>         }
>
>         /**
> diff --git
> a/wicket-core/src/main/java/org/apache/wicket/pageStore/CachingPageStore.java
> b/wicket-core/src/main/java/org/apache/wicket/pageStore/CachingPageStore.java
> new file mode 100644
> index 0000000..d4eff87
> --- /dev/null
> +++
> b/wicket-core/src/main/java/org/apache/wicket/pageStore/CachingPageStore.java
> @@ -0,0 +1,109 @@
> +/*
> + * Licensed to the Apache Software Foundation (ASF) under one or more
> + * contributor license agreements.  See the NOTICE file distributed with
> + * this work for additional information regarding copyright ownership.
> + * The ASF licenses this file to You under the Apache License, Version 2.0
> + * (the "License"); you may not use this file except in compliance with
> + * the License.  You may obtain a copy of the License at
> + *
> + *      http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +package org.apache.wicket.pageStore;
> +
> +import org.apache.wicket.page.IManageablePage;
> +
> +/**
> + * A store of pages that uses an {@link IPageStore} as a cache in front
> of another store to delegate to.
> + */
> +public class CachingPageStore extends DelegatingPageStore
> +{
> +
> +       private IPageStore cache;
> +
> +       /**
> +        * Constructor.
> +        * @param delegate store to delegate to
> +        * @param cache store to use as cache
> +        */
> +       public CachingPageStore(IPageStore delegate, IPageStore cache)
> +       {
> +               super(delegate);
> +
> +               this.cache = cache;
> +       }
> +
> +       /**
> +        * Get the store used a cache.
> +        *
> +        * @return store
> +        */
> +       public IPageStore getCache()
> +       {
> +               return cache;
> +       }
> +
> +       @Override
> +       public IManageablePage getPage(IPageContext context, int id)
> +       {
> +               IManageablePage page = cache.getPage(context, id);
> +               if (page != null) {
> +                       return page;
> +               }
> +
> +               return getDelegate().getPage(context, id);
> +       }
> +
> +       @Override
> +       public void addPage(IPageContext context, IManageablePage page)
> +       {
> +               cache.addPage(context, page);
> +
> +               getDelegate().addPage(context, page);
> +       }
> +
> +       @Override
> +       public void removePage(IPageContext context, IManageablePage page)
> +       {
> +               cache.removePage(context, page);
> +
> +               getDelegate().removePage(context, page);
> +       }
> +
> +       @Override
> +       public void removeAllPages(IPageContext context)
> +       {
> +               cache.removeAllPages(context);
> +
> +               getDelegate().removeAllPages(context);
> +       }
> +
> +       @Override
> +       public void revertPage(IPageContext context, IManageablePage page)
> +       {
> +               cache.revertPage(context, page);
> +
> +               getDelegate().revertPage(context, page);
> +       }
> +
> +       @Override
> +       public void detach(IPageContext context)
> +       {
> +               cache.detach(context);
> +
> +               getDelegate().detach(context);
> +       }
> +
> +       @Override
> +       public void destroy()
> +       {
> +               cache.destroy();
> +
> +               getDelegate().destroy();
> +       }
> +}
> \ No newline at end of file
> diff --git
> a/wicket-core/src/main/java/org/apache/wicket/pageStore/InSessionPageStore.java
> b/wicket-core/src/main/java/org/apache/wicket/pageStore/InSessionPageStore.java
> index 3c363fd..a1beb4d 100644
> ---
> a/wicket-core/src/main/java/org/apache/wicket/pageStore/InSessionPageStore.java
> +++
> b/wicket-core/src/main/java/org/apache/wicket/pageStore/InSessionPageStore.java
> @@ -26,7 +26,6 @@ import java.util.function.Supplier;
>
>  import javax.servlet.http.HttpSession;
>
> -import org.apache.wicket.DefaultPageManagerProvider;
>  import org.apache.wicket.MetaDataKey;
>  import org.apache.wicket.Session;
>  import org.apache.wicket.WicketRuntimeException;
> @@ -39,27 +38,16 @@ import org.apache.wicket.util.lang.Classes;
>  /**
>   * A store keeping a configurable maximum of pages in the session.
>   * <p>
> - * This store can be used in two different ways:
> - * <ul>
> - * <li>as a fast cache in front of a persistent store (as used by {@link
> DefaultPageManagerProvider})</li>
> - * <li>as an application's persistent store of serialized pages in the
> session</li>
> - * </ul>
> + * Note: see {@link #getKey()} for using more than once instance in an
> application
>   */
> -public class InSessionPageStore extends DelegatingPageStore
> +public class InSessionPageStore implements IPageStore
>  {
>
> -       private static final MetaDataKey<SessionData> KEY_CACHE = new
> MetaDataKey<>()
> +       private static final MetaDataKey<SessionData> KEY = new
> MetaDataKey<>()
>         {
>                 private static final long serialVersionUID = 1L;
>         };
>
> -       private static final MetaDataKey<SessionData> KEY_PERSISTENT = new
> MetaDataKey<>()
> -       {
> -               private static final long serialVersionUID = 1L;
> -       };
> -
> -       private final MetaDataKey<SessionData> key;
> -
>         private final ISerializer serializer;
>
>         private final Supplier<SessionData> dataCreator;
> @@ -75,7 +63,7 @@ public class InSessionPageStore extends
> DelegatingPageStore
>          */
>         public InSessionPageStore(int maxPages)
>         {
> -               this(new NoopPageStore(), null, KEY_PERSISTENT, () -> new
> CountLimitedData(maxPages));
> +               this(null, () -> new CountLimitedData(maxPages));
>         }
>
>         /**
> @@ -89,23 +77,7 @@ public class InSessionPageStore extends
> DelegatingPageStore
>          */
>         public InSessionPageStore(Bytes maxBytes)
>         {
> -               this(new NoopPageStore(), null, KEY_PERSISTENT, () -> new
> SizeLimitedData(maxBytes));
> -       }
> -
> -       /**
> -        * Keep a cache of {@code maxPages} in each session.
> -        * <p>
> -        * If the container serializes sessions to disk, any non-{@code
> SerializedPage} added to this
> -        * store will be dropped.
> -        *
> -        * @param delegate
> -        *            store to delegate to
> -        * @param maxPages
> -        *            maximum pages to keep in session
> -        */
> -       public InSessionPageStore(IPageStore delegate, int maxPages)
> -       {
> -               this(delegate, maxPages, null);
> +               this(null, () -> new SizeLimitedData(maxBytes));
>         }
>
>         /**
> @@ -114,26 +86,20 @@ public class InSessionPageStore extends
> DelegatingPageStore
>          * If the container serializes sessions to disk, any non-{@code
> SerializedPage} added to this
>          * store will be automatically serialized.
>          *
> -        * @param delegate
> -        *            store to delegate to
>          * @param maxPages
>          *            maximum pages to keep in session
>          * @param serializer
> -        *            optional serializer used only in case session
> serialization
> +        *            optional serializer used only in case session
> serialization
>          */
> -       public InSessionPageStore(IPageStore delegate, int maxPages,
> ISerializer serializer)
> +       public InSessionPageStore(int maxPages, ISerializer serializer)
>         {
> -               this(delegate, serializer, KEY_CACHE, () -> new
> CountLimitedData(maxPages));
> +               this(serializer, () -> new CountLimitedData(maxPages));
>         }
>
> -       private InSessionPageStore(IPageStore delegate, ISerializer
> serializer, MetaDataKey<SessionData> key, Supplier<SessionData> dataCreator)
> +       private InSessionPageStore(ISerializer serializer,
> Supplier<SessionData> dataCreator)
>         {
> -               super(delegate);
> -
>                 this.serializer = serializer;
>
> -               this.key = key;
> -
>                 this.dataCreator = dataCreator;
>         }
>
> @@ -150,7 +116,7 @@ public class InSessionPageStore extends
> DelegatingPageStore
>                         }
>                 }
>
> -               return getDelegate().getPage(context, id);
> +               return null;
>         }
>
>         @Override
> @@ -159,8 +125,6 @@ public class InSessionPageStore extends
> DelegatingPageStore
>                 SessionData data = getSessionData(context, true);
>
>                 data.add(page);
> -
> -               getDelegate().addPage(context, page);
>         }
>
>         @Override
> @@ -171,8 +135,6 @@ public class InSessionPageStore extends
> DelegatingPageStore
>                 {
>                         data.remove(page.getPageId());
>                 }
> -
> -               getDelegate().removePage(context, page);
>         }
>
>         @Override
> @@ -183,13 +145,11 @@ public class InSessionPageStore extends
> DelegatingPageStore
>                 {
>                         data.removeAll();
>                 }
> -
> -               getDelegate().removeAllPages(context);
>         }
>
>         private SessionData getSessionData(IPageContext context, boolean
> create)
>         {
> -               SessionData data = context.getSessionData(key, () -> {
> +               SessionData data = context.getSessionData(getKey(), () -> {
>                         if (create)
>                         {
>                                 return dataCreator.get();
> @@ -210,10 +170,22 @@ public class InSessionPageStore extends
> DelegatingPageStore
>         }
>
>         /**
> +        * Session data is stored under a {@link MetaDataKey}.
> +        * <p>
> +        * In cases where more than one instance is used in an application
> (e.g. as a fast cache
> +        * <em>and</em> a persistent store of serialized pages in the
> session), this method has to be
> +        * overridden to provide a separate key for each instance.
> +        */
> +       protected MetaDataKey<SessionData> getKey()
> +       {
> +               return KEY;
> +       }
> +
> +       /**
>          * Data kept in the {@link Session}, might get serialized along
> with its containing
>          * {@link HttpSession}.
>          */
> -       abstract static class SessionData implements Serializable
> +       protected abstract static class SessionData implements Serializable
>         {
>
>                 transient ISerializer serializer;
> @@ -402,4 +374,10 @@ public class InSessionPageStore extends
> DelegatingPageStore
>                         size = 0;
>                 }
>         }
> +
> +       @Override
> +       public boolean supportsVersioning()
> +       {
> +               return false;
> +       }
>  }
> diff --git
> a/wicket-core/src/test/java/org/apache/wicket/DefaultPageManagerProviderTest.java
> b/wicket-core/src/test/java/org/apache/wicket/DefaultPageManagerProviderTest.java
> index 5adad4d..7696d9f 100644
> ---
> a/wicket-core/src/test/java/org/apache/wicket/DefaultPageManagerProviderTest.java
> +++
> b/wicket-core/src/test/java/org/apache/wicket/DefaultPageManagerProviderTest.java
> @@ -20,6 +20,7 @@ import static
> org.junit.jupiter.api.Assertions.assertNotNull;
>
>  import org.apache.wicket.page.IPageManager;
>  import org.apache.wicket.pageStore.AsynchronousPageStore;
> +import org.apache.wicket.pageStore.CachingPageStore;
>  import org.apache.wicket.pageStore.DiskPageStore;
>  import org.apache.wicket.pageStore.InSessionPageStore;
>  import org.apache.wicket.pageStore.RequestPageStore;
> @@ -42,8 +43,9 @@ class DefaultPageManagerProviderTest extends
> WicketTestCase
>                 IPageManager manager = new
> DefaultPageManagerProvider(tester.getApplication()).get();
>
>                 RequestPageStore request =
> (RequestPageStore)manager.getPageStore();
> -               InSessionPageStore session =
> (InSessionPageStore)request.getDelegate();
> -               AsynchronousPageStore asynchronous =
> (AsynchronousPageStore)session.getDelegate();
> +               CachingPageStore caching =
> (CachingPageStore)request.getDelegate();
> +               InSessionPageStore session =
> (InSessionPageStore)caching.getCache();
> +               AsynchronousPageStore asynchronous =
> (AsynchronousPageStore)caching.getDelegate();
>                 SerializingPageStore serializing =
> (SerializingPageStore)asynchronous.getDelegate();
>                 DiskPageStore disk =
> (DiskPageStore)serializing.getDelegate();
>
> diff --git
> a/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/TestMapperContext.java
> b/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/TestMapperContext.java
> index 6f3be0f..1f163a2 100644
> ---
> a/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/TestMapperContext.java
> +++
> b/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/TestMapperContext.java
> @@ -23,7 +23,9 @@ import org.apache.wicket.markup.MarkupParser;
>  import org.apache.wicket.mock.MockPageContext;
>  import org.apache.wicket.page.IPageManager;
>  import org.apache.wicket.page.PageManager;
> +import org.apache.wicket.pageStore.CachingPageStore;
>  import org.apache.wicket.pageStore.IPageContext;
> +import org.apache.wicket.pageStore.IPageStore;
>  import org.apache.wicket.pageStore.InMemoryPageStore;
>  import org.apache.wicket.pageStore.InSessionPageStore;
>  import org.apache.wicket.pageStore.RequestPageStore;
> @@ -44,7 +46,7 @@ public class TestMapperContext implements IMapperContext
>         private static final String APP_NAME = "test_app";
>         private static int count;
>
> -       InSessionPageStore pageStore;
> +       IPageStore pageStore;
>         MockPageContext pageContext;
>         IPageManager pageManager;
>         private String appName;
> @@ -60,7 +62,8 @@ public class TestMapperContext implements IMapperContext
>                 pageContext = new MockPageContext();
>
>                 InMemoryPageStore inMemoryPageStore = new
> InMemoryPageStore(appName, Integer.MAX_VALUE);
> -               pageStore = new InSessionPageStore(inMemoryPageStore, 4,
> new JavaSerializer(appName));
> +               InSessionPageStore inSessionPageStore = new
> InSessionPageStore(4, new JavaSerializer(appName));
> +               pageStore = new CachingPageStore(inMemoryPageStore,
> inSessionPageStore);
>                 pageManager = new PageManager(new
> RequestPageStore(pageStore)) {
>                         @Override
>                         protected IPageContext createPageContext()
> diff --git
> a/wicket-core/src/test/java/org/apache/wicket/page/PersistentPageManagerTest.java
> b/wicket-core/src/test/java/org/apache/wicket/page/PersistentPageManagerTest.java
> index 77bb7f0..300f18b 100644
> ---
> a/wicket-core/src/test/java/org/apache/wicket/page/PersistentPageManagerTest.java
> +++
> b/wicket-core/src/test/java/org/apache/wicket/page/PersistentPageManagerTest.java
> @@ -105,7 +105,7 @@ class PersistentPageManagerTest
>          */
>         private IPageManager createPageManager(String appName,
> AtomicReference<Object> sessionData)
>         {
> -               IPageStore store = new InSessionPageStore(new
> NoopPageStore(), Integer.MAX_VALUE, new JavaSerializer(APP_NAME));
> +               IPageStore store = new
> InSessionPageStore(Integer.MAX_VALUE, new JavaSerializer(APP_NAME));
>
>                 return new PageManager(store) {
>                         @Override
> diff --git
> a/wicket-core/src/test/java/org/apache/wicket/pageStore/InSessionPageStoreTest.java
> b/wicket-core/src/test/java/org/apache/wicket/pageStore/InSessionPageStoreTest.java
> index 301a33c..6bd00a5 100644
> ---
> a/wicket-core/src/test/java/org/apache/wicket/pageStore/InSessionPageStoreTest.java
> +++
> b/wicket-core/src/test/java/org/apache/wicket/pageStore/InSessionPageStoreTest.java
> @@ -16,15 +16,31 @@
>   */
>  package org.apache.wicket.pageStore;
>
> +import org.apache.wicket.MetaDataKey;
> +import org.apache.wicket.pageStore.InSessionPageStore.SessionData;
> +
>  /**
>   * Test for {@link InSessionPageStore}.
>   */
>  public class InSessionPageStoreTest extends AbstractPageStoreTest
>  {
> +
> +       private static final MetaDataKey<SessionData> KEY = new
> MetaDataKey<SessionData>()
> +       {
> +               private static final long serialVersionUID = 1L;
> +       };
> +
>         @Override
>         protected IPageStore createPageStore(int maxEntries)
>         {
> -               return new InSessionPageStore(new NoopPageStore(),
> maxEntries);
> +               return new InSessionPageStore(maxEntries) {
> +
> +                       @Override
> +                       protected MetaDataKey<SessionData> getKey()
> +                       {
> +                               return KEY;
> +                       }
> +               };
>         }
>
>  }
> diff --git
> a/wicket-core/src/test/java/org/apache/wicket/versioning/PageVersioningTest.java
> b/wicket-core/src/test/java/org/apache/wicket/versioning/PageVersioningTest.java
> index 3842780..e882bab 100644
> ---
> a/wicket-core/src/test/java/org/apache/wicket/versioning/PageVersioningTest.java
> +++
> b/wicket-core/src/test/java/org/apache/wicket/versioning/PageVersioningTest.java
> @@ -23,6 +23,7 @@ import org.apache.wicket.IPageManagerProvider;
>  import org.apache.wicket.Page;
>  import org.apache.wicket.page.IPageManager;
>  import org.apache.wicket.page.PageManager;
> +import org.apache.wicket.pageStore.CachingPageStore;
>  import org.apache.wicket.pageStore.IPageStore;
>  import org.apache.wicket.pageStore.InMemoryPageStore;
>  import org.apache.wicket.pageStore.InSessionPageStore;
> @@ -62,7 +63,8 @@ class PageVersioningTest
>                                 {
>                                         InMemoryPageStore inMemory = new
> InMemoryPageStore("test", Integer.MAX_VALUE);
>                                         SerializingPageStore serializing =
> new SerializingPageStore(inMemory, new JavaSerializer("test"));
> -                                       final IPageStore store = new
> InSessionPageStore(serializing, Integer.MAX_VALUE);
> +                                       InSessionPageStore session = new
> InSessionPageStore(Integer.MAX_VALUE);
> +                                       final IPageStore store = new
> CachingPageStore(serializing, session);
>                                         return new PageManager(store);
>                                 };
>                         }
>
>

-- 
WBR
Maxim aka solomax

Re: [wicket] branch master updated: WICKET-6563 add CachingPageStore

Posted by Sven Meier <sv...@meiers.net>.
Hi Maxim,

no changes required.

Thanks for asking

Sven

On 27.03.20 14:24, Maxim Solodovnik wrote:
> Hello Sven,
>
> Are there any changes for wicketstuff-datastore required?
>
> On Fri, 27 Mar 2020 at 20:18, <sv...@apache.org> wrote:
>
>> This is an automated email from the ASF dual-hosted git repository.
>>
>> svenmeier pushed a commit to branch master
>> in repository https://gitbox.apache.org/repos/asf/wicket.git
>>
>>
>> The following commit(s) were added to refs/heads/master by this push:
>>       new 8df3528  WICKET-6563 add CachingPageStore
>> 8df3528 is described below
>>
>> commit 8df3528dc44a08b7d375c20e764a3664cd6a5f30
>> Author: Sven Meier <sv...@apache.org>
>> AuthorDate: Fri Mar 27 10:13:13 2020 +0100
>>
>>      WICKET-6563 add CachingPageStore
>> ---
>>   .../apache/wicket/DefaultPageManagerProvider.java  |   9 +-
>>   .../apache/wicket/pageStore/CachingPageStore.java  | 109
>> +++++++++++++++++++++
>>   .../wicket/pageStore/InSessionPageStore.java       |  82 ++++++----------
>>   .../wicket/DefaultPageManagerProviderTest.java     |   6 +-
>>   .../core/request/mapper/TestMapperContext.java     |   7 +-
>>   .../wicket/page/PersistentPageManagerTest.java     |   2 +-
>>   .../wicket/pageStore/InSessionPageStoreTest.java   |  18 +++-
>>   .../wicket/versioning/PageVersioningTest.java      |   4 +-
>>   8 files changed, 174 insertions(+), 63 deletions(-)
>>
>> diff --git
>> a/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
>> b/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
>> index e128266..540b1b3 100644
>> ---
>> a/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
>> +++
>> b/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
>> @@ -21,6 +21,7 @@ import java.io.File;
>>   import org.apache.wicket.page.IPageManager;
>>   import org.apache.wicket.page.PageManager;
>>   import org.apache.wicket.pageStore.AsynchronousPageStore;
>> +import org.apache.wicket.pageStore.CachingPageStore;
>>   import org.apache.wicket.pageStore.CryptingPageStore;
>>   import org.apache.wicket.pageStore.DiskPageStore;
>>   import org.apache.wicket.pageStore.FilePageStore;
>> @@ -103,7 +104,7 @@ public class DefaultPageManagerProvider implements
>> IPageManagerProvider
>>
>>                  store = newAsynchronousStore(store);
>>
>> -               store = newSessionStore(store);
>> +               store = newCachingStore(store);
>>
>>                  store = newRequestStore(store);
>>
>> @@ -125,7 +126,7 @@ public class DefaultPageManagerProvider implements
>> IPageManagerProvider
>>          }
>>
>>          /**
>> -        * Cache pages in the request until it is finished.
>> +        * Keep pages in the request until it is finished.
>>           *
>>           * @see RequestPageStore
>>           */
>> @@ -139,9 +140,9 @@ public class DefaultPageManagerProvider implements
>> IPageManagerProvider
>>           *
>>           * @see InSessionPageStore
>>           */
>> -       protected IPageStore newSessionStore(IPageStore pageStore)
>> +       protected IPageStore newCachingStore(IPageStore pageStore)
>>          {
>> -               return new InSessionPageStore(pageStore, 1,
>> getSerializer());
>> +               return new CachingPageStore(pageStore, new
>> InSessionPageStore(1, getSerializer()));
>>          }
>>
>>          /**
>> diff --git
>> a/wicket-core/src/main/java/org/apache/wicket/pageStore/CachingPageStore.java
>> b/wicket-core/src/main/java/org/apache/wicket/pageStore/CachingPageStore.java
>> new file mode 100644
>> index 0000000..d4eff87
>> --- /dev/null
>> +++
>> b/wicket-core/src/main/java/org/apache/wicket/pageStore/CachingPageStore.java
>> @@ -0,0 +1,109 @@
>> +/*
>> + * Licensed to the Apache Software Foundation (ASF) under one or more
>> + * contributor license agreements.  See the NOTICE file distributed with
>> + * this work for additional information regarding copyright ownership.
>> + * The ASF licenses this file to You under the Apache License, Version 2.0
>> + * (the "License"); you may not use this file except in compliance with
>> + * the License.  You may obtain a copy of the License at
>> + *
>> + *      http://www.apache.org/licenses/LICENSE-2.0
>> + *
>> + * Unless required by applicable law or agreed to in writing, software
>> + * distributed under the License is distributed on an "AS IS" BASIS,
>> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
>> implied.
>> + * See the License for the specific language governing permissions and
>> + * limitations under the License.
>> + */
>> +package org.apache.wicket.pageStore;
>> +
>> +import org.apache.wicket.page.IManageablePage;
>> +
>> +/**
>> + * A store of pages that uses an {@link IPageStore} as a cache in front
>> of another store to delegate to.
>> + */
>> +public class CachingPageStore extends DelegatingPageStore
>> +{
>> +
>> +       private IPageStore cache;
>> +
>> +       /**
>> +        * Constructor.
>> +        * @param delegate store to delegate to
>> +        * @param cache store to use as cache
>> +        */
>> +       public CachingPageStore(IPageStore delegate, IPageStore cache)
>> +       {
>> +               super(delegate);
>> +
>> +               this.cache = cache;
>> +       }
>> +
>> +       /**
>> +        * Get the store used a cache.
>> +        *
>> +        * @return store
>> +        */
>> +       public IPageStore getCache()
>> +       {
>> +               return cache;
>> +       }
>> +
>> +       @Override
>> +       public IManageablePage getPage(IPageContext context, int id)
>> +       {
>> +               IManageablePage page = cache.getPage(context, id);
>> +               if (page != null) {
>> +                       return page;
>> +               }
>> +
>> +               return getDelegate().getPage(context, id);
>> +       }
>> +
>> +       @Override
>> +       public void addPage(IPageContext context, IManageablePage page)
>> +       {
>> +               cache.addPage(context, page);
>> +
>> +               getDelegate().addPage(context, page);
>> +       }
>> +
>> +       @Override
>> +       public void removePage(IPageContext context, IManageablePage page)
>> +       {
>> +               cache.removePage(context, page);
>> +
>> +               getDelegate().removePage(context, page);
>> +       }
>> +
>> +       @Override
>> +       public void removeAllPages(IPageContext context)
>> +       {
>> +               cache.removeAllPages(context);
>> +
>> +               getDelegate().removeAllPages(context);
>> +       }
>> +
>> +       @Override
>> +       public void revertPage(IPageContext context, IManageablePage page)
>> +       {
>> +               cache.revertPage(context, page);
>> +
>> +               getDelegate().revertPage(context, page);
>> +       }
>> +
>> +       @Override
>> +       public void detach(IPageContext context)
>> +       {
>> +               cache.detach(context);
>> +
>> +               getDelegate().detach(context);
>> +       }
>> +
>> +       @Override
>> +       public void destroy()
>> +       {
>> +               cache.destroy();
>> +
>> +               getDelegate().destroy();
>> +       }
>> +}
>> \ No newline at end of file
>> diff --git
>> a/wicket-core/src/main/java/org/apache/wicket/pageStore/InSessionPageStore.java
>> b/wicket-core/src/main/java/org/apache/wicket/pageStore/InSessionPageStore.java
>> index 3c363fd..a1beb4d 100644
>> ---
>> a/wicket-core/src/main/java/org/apache/wicket/pageStore/InSessionPageStore.java
>> +++
>> b/wicket-core/src/main/java/org/apache/wicket/pageStore/InSessionPageStore.java
>> @@ -26,7 +26,6 @@ import java.util.function.Supplier;
>>
>>   import javax.servlet.http.HttpSession;
>>
>> -import org.apache.wicket.DefaultPageManagerProvider;
>>   import org.apache.wicket.MetaDataKey;
>>   import org.apache.wicket.Session;
>>   import org.apache.wicket.WicketRuntimeException;
>> @@ -39,27 +38,16 @@ import org.apache.wicket.util.lang.Classes;
>>   /**
>>    * A store keeping a configurable maximum of pages in the session.
>>    * <p>
>> - * This store can be used in two different ways:
>> - * <ul>
>> - * <li>as a fast cache in front of a persistent store (as used by {@link
>> DefaultPageManagerProvider})</li>
>> - * <li>as an application's persistent store of serialized pages in the
>> session</li>
>> - * </ul>
>> + * Note: see {@link #getKey()} for using more than once instance in an
>> application
>>    */
>> -public class InSessionPageStore extends DelegatingPageStore
>> +public class InSessionPageStore implements IPageStore
>>   {
>>
>> -       private static final MetaDataKey<SessionData> KEY_CACHE = new
>> MetaDataKey<>()
>> +       private static final MetaDataKey<SessionData> KEY = new
>> MetaDataKey<>()
>>          {
>>                  private static final long serialVersionUID = 1L;
>>          };
>>
>> -       private static final MetaDataKey<SessionData> KEY_PERSISTENT = new
>> MetaDataKey<>()
>> -       {
>> -               private static final long serialVersionUID = 1L;
>> -       };
>> -
>> -       private final MetaDataKey<SessionData> key;
>> -
>>          private final ISerializer serializer;
>>
>>          private final Supplier<SessionData> dataCreator;
>> @@ -75,7 +63,7 @@ public class InSessionPageStore extends
>> DelegatingPageStore
>>           */
>>          public InSessionPageStore(int maxPages)
>>          {
>> -               this(new NoopPageStore(), null, KEY_PERSISTENT, () -> new
>> CountLimitedData(maxPages));
>> +               this(null, () -> new CountLimitedData(maxPages));
>>          }
>>
>>          /**
>> @@ -89,23 +77,7 @@ public class InSessionPageStore extends
>> DelegatingPageStore
>>           */
>>          public InSessionPageStore(Bytes maxBytes)
>>          {
>> -               this(new NoopPageStore(), null, KEY_PERSISTENT, () -> new
>> SizeLimitedData(maxBytes));
>> -       }
>> -
>> -       /**
>> -        * Keep a cache of {@code maxPages} in each session.
>> -        * <p>
>> -        * If the container serializes sessions to disk, any non-{@code
>> SerializedPage} added to this
>> -        * store will be dropped.
>> -        *
>> -        * @param delegate
>> -        *            store to delegate to
>> -        * @param maxPages
>> -        *            maximum pages to keep in session
>> -        */
>> -       public InSessionPageStore(IPageStore delegate, int maxPages)
>> -       {
>> -               this(delegate, maxPages, null);
>> +               this(null, () -> new SizeLimitedData(maxBytes));
>>          }
>>
>>          /**
>> @@ -114,26 +86,20 @@ public class InSessionPageStore extends
>> DelegatingPageStore
>>           * If the container serializes sessions to disk, any non-{@code
>> SerializedPage} added to this
>>           * store will be automatically serialized.
>>           *
>> -        * @param delegate
>> -        *            store to delegate to
>>           * @param maxPages
>>           *            maximum pages to keep in session
>>           * @param serializer
>> -        *            optional serializer used only in case session
>> serialization
>> +        *            optional serializer used only in case session
>> serialization
>>           */
>> -       public InSessionPageStore(IPageStore delegate, int maxPages,
>> ISerializer serializer)
>> +       public InSessionPageStore(int maxPages, ISerializer serializer)
>>          {
>> -               this(delegate, serializer, KEY_CACHE, () -> new
>> CountLimitedData(maxPages));
>> +               this(serializer, () -> new CountLimitedData(maxPages));
>>          }
>>
>> -       private InSessionPageStore(IPageStore delegate, ISerializer
>> serializer, MetaDataKey<SessionData> key, Supplier<SessionData> dataCreator)
>> +       private InSessionPageStore(ISerializer serializer,
>> Supplier<SessionData> dataCreator)
>>          {
>> -               super(delegate);
>> -
>>                  this.serializer = serializer;
>>
>> -               this.key = key;
>> -
>>                  this.dataCreator = dataCreator;
>>          }
>>
>> @@ -150,7 +116,7 @@ public class InSessionPageStore extends
>> DelegatingPageStore
>>                          }
>>                  }
>>
>> -               return getDelegate().getPage(context, id);
>> +               return null;
>>          }
>>
>>          @Override
>> @@ -159,8 +125,6 @@ public class InSessionPageStore extends
>> DelegatingPageStore
>>                  SessionData data = getSessionData(context, true);
>>
>>                  data.add(page);
>> -
>> -               getDelegate().addPage(context, page);
>>          }
>>
>>          @Override
>> @@ -171,8 +135,6 @@ public class InSessionPageStore extends
>> DelegatingPageStore
>>                  {
>>                          data.remove(page.getPageId());
>>                  }
>> -
>> -               getDelegate().removePage(context, page);
>>          }
>>
>>          @Override
>> @@ -183,13 +145,11 @@ public class InSessionPageStore extends
>> DelegatingPageStore
>>                  {
>>                          data.removeAll();
>>                  }
>> -
>> -               getDelegate().removeAllPages(context);
>>          }
>>
>>          private SessionData getSessionData(IPageContext context, boolean
>> create)
>>          {
>> -               SessionData data = context.getSessionData(key, () -> {
>> +               SessionData data = context.getSessionData(getKey(), () -> {
>>                          if (create)
>>                          {
>>                                  return dataCreator.get();
>> @@ -210,10 +170,22 @@ public class InSessionPageStore extends
>> DelegatingPageStore
>>          }
>>
>>          /**
>> +        * Session data is stored under a {@link MetaDataKey}.
>> +        * <p>
>> +        * In cases where more than one instance is used in an application
>> (e.g. as a fast cache
>> +        * <em>and</em> a persistent store of serialized pages in the
>> session), this method has to be
>> +        * overridden to provide a separate key for each instance.
>> +        */
>> +       protected MetaDataKey<SessionData> getKey()
>> +       {
>> +               return KEY;
>> +       }
>> +
>> +       /**
>>           * Data kept in the {@link Session}, might get serialized along
>> with its containing
>>           * {@link HttpSession}.
>>           */
>> -       abstract static class SessionData implements Serializable
>> +       protected abstract static class SessionData implements Serializable
>>          {
>>
>>                  transient ISerializer serializer;
>> @@ -402,4 +374,10 @@ public class InSessionPageStore extends
>> DelegatingPageStore
>>                          size = 0;
>>                  }
>>          }
>> +
>> +       @Override
>> +       public boolean supportsVersioning()
>> +       {
>> +               return false;
>> +       }
>>   }
>> diff --git
>> a/wicket-core/src/test/java/org/apache/wicket/DefaultPageManagerProviderTest.java
>> b/wicket-core/src/test/java/org/apache/wicket/DefaultPageManagerProviderTest.java
>> index 5adad4d..7696d9f 100644
>> ---
>> a/wicket-core/src/test/java/org/apache/wicket/DefaultPageManagerProviderTest.java
>> +++
>> b/wicket-core/src/test/java/org/apache/wicket/DefaultPageManagerProviderTest.java
>> @@ -20,6 +20,7 @@ import static
>> org.junit.jupiter.api.Assertions.assertNotNull;
>>
>>   import org.apache.wicket.page.IPageManager;
>>   import org.apache.wicket.pageStore.AsynchronousPageStore;
>> +import org.apache.wicket.pageStore.CachingPageStore;
>>   import org.apache.wicket.pageStore.DiskPageStore;
>>   import org.apache.wicket.pageStore.InSessionPageStore;
>>   import org.apache.wicket.pageStore.RequestPageStore;
>> @@ -42,8 +43,9 @@ class DefaultPageManagerProviderTest extends
>> WicketTestCase
>>                  IPageManager manager = new
>> DefaultPageManagerProvider(tester.getApplication()).get();
>>
>>                  RequestPageStore request =
>> (RequestPageStore)manager.getPageStore();
>> -               InSessionPageStore session =
>> (InSessionPageStore)request.getDelegate();
>> -               AsynchronousPageStore asynchronous =
>> (AsynchronousPageStore)session.getDelegate();
>> +               CachingPageStore caching =
>> (CachingPageStore)request.getDelegate();
>> +               InSessionPageStore session =
>> (InSessionPageStore)caching.getCache();
>> +               AsynchronousPageStore asynchronous =
>> (AsynchronousPageStore)caching.getDelegate();
>>                  SerializingPageStore serializing =
>> (SerializingPageStore)asynchronous.getDelegate();
>>                  DiskPageStore disk =
>> (DiskPageStore)serializing.getDelegate();
>>
>> diff --git
>> a/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/TestMapperContext.java
>> b/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/TestMapperContext.java
>> index 6f3be0f..1f163a2 100644
>> ---
>> a/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/TestMapperContext.java
>> +++
>> b/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/TestMapperContext.java
>> @@ -23,7 +23,9 @@ import org.apache.wicket.markup.MarkupParser;
>>   import org.apache.wicket.mock.MockPageContext;
>>   import org.apache.wicket.page.IPageManager;
>>   import org.apache.wicket.page.PageManager;
>> +import org.apache.wicket.pageStore.CachingPageStore;
>>   import org.apache.wicket.pageStore.IPageContext;
>> +import org.apache.wicket.pageStore.IPageStore;
>>   import org.apache.wicket.pageStore.InMemoryPageStore;
>>   import org.apache.wicket.pageStore.InSessionPageStore;
>>   import org.apache.wicket.pageStore.RequestPageStore;
>> @@ -44,7 +46,7 @@ public class TestMapperContext implements IMapperContext
>>          private static final String APP_NAME = "test_app";
>>          private static int count;
>>
>> -       InSessionPageStore pageStore;
>> +       IPageStore pageStore;
>>          MockPageContext pageContext;
>>          IPageManager pageManager;
>>          private String appName;
>> @@ -60,7 +62,8 @@ public class TestMapperContext implements IMapperContext
>>                  pageContext = new MockPageContext();
>>
>>                  InMemoryPageStore inMemoryPageStore = new
>> InMemoryPageStore(appName, Integer.MAX_VALUE);
>> -               pageStore = new InSessionPageStore(inMemoryPageStore, 4,
>> new JavaSerializer(appName));
>> +               InSessionPageStore inSessionPageStore = new
>> InSessionPageStore(4, new JavaSerializer(appName));
>> +               pageStore = new CachingPageStore(inMemoryPageStore,
>> inSessionPageStore);
>>                  pageManager = new PageManager(new
>> RequestPageStore(pageStore)) {
>>                          @Override
>>                          protected IPageContext createPageContext()
>> diff --git
>> a/wicket-core/src/test/java/org/apache/wicket/page/PersistentPageManagerTest.java
>> b/wicket-core/src/test/java/org/apache/wicket/page/PersistentPageManagerTest.java
>> index 77bb7f0..300f18b 100644
>> ---
>> a/wicket-core/src/test/java/org/apache/wicket/page/PersistentPageManagerTest.java
>> +++
>> b/wicket-core/src/test/java/org/apache/wicket/page/PersistentPageManagerTest.java
>> @@ -105,7 +105,7 @@ class PersistentPageManagerTest
>>           */
>>          private IPageManager createPageManager(String appName,
>> AtomicReference<Object> sessionData)
>>          {
>> -               IPageStore store = new InSessionPageStore(new
>> NoopPageStore(), Integer.MAX_VALUE, new JavaSerializer(APP_NAME));
>> +               IPageStore store = new
>> InSessionPageStore(Integer.MAX_VALUE, new JavaSerializer(APP_NAME));
>>
>>                  return new PageManager(store) {
>>                          @Override
>> diff --git
>> a/wicket-core/src/test/java/org/apache/wicket/pageStore/InSessionPageStoreTest.java
>> b/wicket-core/src/test/java/org/apache/wicket/pageStore/InSessionPageStoreTest.java
>> index 301a33c..6bd00a5 100644
>> ---
>> a/wicket-core/src/test/java/org/apache/wicket/pageStore/InSessionPageStoreTest.java
>> +++
>> b/wicket-core/src/test/java/org/apache/wicket/pageStore/InSessionPageStoreTest.java
>> @@ -16,15 +16,31 @@
>>    */
>>   package org.apache.wicket.pageStore;
>>
>> +import org.apache.wicket.MetaDataKey;
>> +import org.apache.wicket.pageStore.InSessionPageStore.SessionData;
>> +
>>   /**
>>    * Test for {@link InSessionPageStore}.
>>    */
>>   public class InSessionPageStoreTest extends AbstractPageStoreTest
>>   {
>> +
>> +       private static final MetaDataKey<SessionData> KEY = new
>> MetaDataKey<SessionData>()
>> +       {
>> +               private static final long serialVersionUID = 1L;
>> +       };
>> +
>>          @Override
>>          protected IPageStore createPageStore(int maxEntries)
>>          {
>> -               return new InSessionPageStore(new NoopPageStore(),
>> maxEntries);
>> +               return new InSessionPageStore(maxEntries) {
>> +
>> +                       @Override
>> +                       protected MetaDataKey<SessionData> getKey()
>> +                       {
>> +                               return KEY;
>> +                       }
>> +               };
>>          }
>>
>>   }
>> diff --git
>> a/wicket-core/src/test/java/org/apache/wicket/versioning/PageVersioningTest.java
>> b/wicket-core/src/test/java/org/apache/wicket/versioning/PageVersioningTest.java
>> index 3842780..e882bab 100644
>> ---
>> a/wicket-core/src/test/java/org/apache/wicket/versioning/PageVersioningTest.java
>> +++
>> b/wicket-core/src/test/java/org/apache/wicket/versioning/PageVersioningTest.java
>> @@ -23,6 +23,7 @@ import org.apache.wicket.IPageManagerProvider;
>>   import org.apache.wicket.Page;
>>   import org.apache.wicket.page.IPageManager;
>>   import org.apache.wicket.page.PageManager;
>> +import org.apache.wicket.pageStore.CachingPageStore;
>>   import org.apache.wicket.pageStore.IPageStore;
>>   import org.apache.wicket.pageStore.InMemoryPageStore;
>>   import org.apache.wicket.pageStore.InSessionPageStore;
>> @@ -62,7 +63,8 @@ class PageVersioningTest
>>                                  {
>>                                          InMemoryPageStore inMemory = new
>> InMemoryPageStore("test", Integer.MAX_VALUE);
>>                                          SerializingPageStore serializing =
>> new SerializingPageStore(inMemory, new JavaSerializer("test"));
>> -                                       final IPageStore store = new
>> InSessionPageStore(serializing, Integer.MAX_VALUE);
>> +                                       InSessionPageStore session = new
>> InSessionPageStore(Integer.MAX_VALUE);
>> +                                       final IPageStore store = new
>> CachingPageStore(serializing, session);
>>                                          return new PageManager(store);
>>                                  };
>>                          }
>>
>>