Repository: wicket
Updated Branches:
  refs/heads/WICKET-6563 bcf76f517 -> a3604f7c3


WICKET-6563 allow passing of SerializedPage

between page stores


Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/a3604f7c
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/a3604f7c
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/a3604f7c

Branch: refs/heads/WICKET-6563
Commit: a3604f7c359f9bbd2df03d57831c3f0d838ef521
Parents: bcf76f5
Author: Sven Meier <[email protected]>
Authored: Tue Jul 3 20:18:10 2018 +0200
Committer: Sven Meier <[email protected]>
Committed: Tue Jul 3 20:18:25 2018 +0200

----------------------------------------------------------------------
 .../wicket/DefaultPageManagerProvider.java      |   4 +-
 .../apache/wicket/pageStore/DiskPageStore.java  |  11 +-
 .../wicket/pageStore/InSessionPageStore.java    | 115 +++++++++----------
 .../apache/wicket/pageStore/SerializedPage.java |  74 ++++++++++++
 .../wicket/pageStore/SerializingPageStore.java  |  63 ++++++++++
 .../wicket/versioning/PageVersioningTest.java   |   7 +-
 6 files changed, 207 insertions(+), 67 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/a3604f7c/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
----------------------------------------------------------------------
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 c800935..0539355 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
+++ 
b/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
@@ -28,6 +28,7 @@ import org.apache.wicket.pageStore.InMemoryPageStore;
 import org.apache.wicket.pageStore.InSessionPageStore;
 import org.apache.wicket.pageStore.NoopPageStore;
 import org.apache.wicket.pageStore.RequestPageStore;
+import org.apache.wicket.pageStore.SerializingPageStore;
 import org.apache.wicket.serialize.ISerializer;
 import org.apache.wicket.settings.StoreSettings;
 import org.apache.wicket.util.lang.Args;
@@ -45,9 +46,10 @@ import org.apache.wicket.util.lang.Bytes;
  * <ul>
  * <li>{@link RequestPageStore} caching pages until end of the request</li>
  * <li>{@link InSessionPageStore} keeping the last accessed page in the 
session</li>
+ * <li>{@link SerializingPageStore} serializing all pages (so they are 
available for back-button </li>
  * <li>{@link InMemoryPageStore} keeping all pages</li>
  * </ul>
- * ... or if all pages should be kept in the session only:
+ * ... or if all pages should be kept in the session only without any 
serialization (no back-button support)
  * <ul>
  * <li>{@link RequestPageStore} caching pages until end of the request</li>
  * <li>{@link InSessionPageStore} keeping a limited count of pages in the 
session, e.g. 10</li>

http://git-wip-us.apache.org/repos/asf/wicket/blob/a3604f7c/wicket-core/src/main/java/org/apache/wicket/pageStore/DiskPageStore.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/pageStore/DiskPageStore.java 
b/wicket-core/src/main/java/org/apache/wicket/pageStore/DiskPageStore.java
index b810218..85bed3e 100644
--- a/wicket-core/src/main/java/org/apache/wicket/pageStore/DiskPageStore.java
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/DiskPageStore.java
@@ -188,6 +188,10 @@ public class DiskPageStore implements IPersistentPageStore
                }
        }
 
+       /**
+        * Supports {@link SerializedPage}s too - for this to work the 
delegating
+        * {@link IPageStore} must use the same {@link ISerializer} as this one.
+        */
        @Override
        public void addPage(IPageContext context, IManageablePage page)
        {
@@ -196,7 +200,12 @@ public class DiskPageStore implements IPersistentPageStore
                {
                        log.debug("Storing data for page with id '{}' in 
session with id '{}'", page.getPageId(), context.getSessionId());
                        
-                       byte[] data = serializer.serialize(page);
+                       byte[] data;
+                       if (page instanceof SerializedPage) {
+                               data = ((SerializedPage)page).getData();
+                       } else {
+                               data = serializer.serialize(page);
+                       }
                        
                        diskData.savePage(page.getPageId(), page.getClass(), 
data);
                }

http://git-wip-us.apache.org/repos/asf/wicket/blob/a3604f7c/wicket-core/src/main/java/org/apache/wicket/pageStore/InSessionPageStore.java
----------------------------------------------------------------------
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 3914464..e3d3e07 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
@@ -20,11 +20,12 @@ import java.io.IOException;
 import java.io.ObjectOutputStream;
 import java.io.Serializable;
 import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.Map.Entry;
+import java.util.LinkedList;
+import java.util.List;
 
 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;
@@ -33,8 +34,10 @@ import org.apache.wicket.serialize.ISerializer;
 import org.apache.wicket.util.lang.Args;
 
 /**
- * A store keeping a configurable maximum of pages in the session, delegating 
all or excessive pages
- * to another store.
+ * A store keeping a configurable maximum of pages in the session.
+ * <p>
+ * This store is used by {@link DefaultPageManagerProvider} as a cache in 
front 
+ * of a persistent store.
  */
 public class InSessionPageStore extends DelegatingPageStore
 {
@@ -47,9 +50,7 @@ public class InSessionPageStore extends DelegatingPageStore
        private ISerializer serializer;
 
        private int maxPages;
-
-       private boolean delegateAll = false;
-
+       
        /**
         * Use this constructor, if sessions are never serialized.
         * 
@@ -93,16 +94,6 @@ public class InSessionPageStore extends DelegatingPageStore
                this.maxPages = maxPages;
        }
 
-       /**
-        * Delegated all pages, even those that are still kept in the session.
-        */
-       public InSessionPageStore delegateAll()
-       {
-               delegateAll = true;
-
-               return this;
-       }
-
        @Override
        public IManageablePage getPage(IPageContext context, int id)
        {
@@ -120,7 +111,9 @@ public class InSessionPageStore extends DelegatingPageStore
        {
                SessionData data = getSessionData(context);
 
-               data.addAndDelegate(context, page, maxPages, delegateAll, 
getDelegate());
+               data.add(context, page, maxPages);
+               
+               super.addPage(context, page);
        }
 
        @Override
@@ -167,8 +160,10 @@ public class InSessionPageStore extends DelegatingPageStore
 
                /**
                 * Pages, may partly be serialized.
+                * <p>
+                * Kept in list instead of map, since life pages might change 
their id during a request.
                 */
-               private LinkedHashMap<Integer, Serializable> pages = new 
LinkedHashMap<>();
+               private List<IManageablePage> pages = new LinkedList<>();
 
                /**
                 * This method <em>must</em> be called each time it is 
retrieved from the session: <br/>
@@ -180,45 +175,27 @@ public class InSessionPageStore extends 
DelegatingPageStore
                        this.serializer = Args.notNull(serializer, 
"serializer");
                }
 
-               public synchronized void addAndDelegate(IPageContext context, 
IManageablePage page,
-                       int maxPages, boolean delegateAll, IPageStore delegate)
+               public synchronized void add(IPageContext context, 
IManageablePage page, int maxPages)
                {
-                       pages.remove(page.getPageId());
-                       pages.put(page.getPageId(), page);
+                       // move to end
+                       remove(page);
+                       pages.add(page);
 
-                       Serializable expelled = null;
-                       if (pages.size() > maxPages)
-                       {
-                               Iterator<Serializable> iterator = 
pages.values().iterator();
-                               expelled = iterator.next();
-                               iterator.remove();
-                       }
-
-                       if (delegateAll)
-                       {
-                               delegate.addPage(context, page);
-                       }
-                       else
+                       while (pages.size() > maxPages)
                        {
-                               // when pages are not delegated automatically, 
we have to catch up
-                               // on an expelled page now
-                               if (expelled != null)
-                               {
-                                       if (expelled instanceof byte[])
-                                       {
-                                               // ... which results in this 
suboptimal case, when the session was persisted:
-                                               // in that case the expelled 
page is still in a serialized state, so we have
-                                               // to deserialize it first to 
be able to delegate it 
-                                               expelled = 
(IManageablePage)serializer.deserialize((byte[])expelled);
-                                       }
-                                       delegate.addPage(context, 
(IManageablePage)expelled);
-                               }
+                               pages.remove(0);
                        }
                }
 
                public synchronized void remove(IManageablePage page)
                {
-                       pages.remove(page.getPageId());
+                       Iterator<IManageablePage> iterator = pages.iterator();
+                       while (iterator.hasNext()) {
+                               if (iterator.next().getPageId() == 
page.getPageId()) {
+                                       iterator.remove();
+                                       break;
+                               }
+                       }
                }
 
                public synchronized void removeAll()
@@ -228,20 +205,30 @@ public class InSessionPageStore extends 
DelegatingPageStore
 
                public synchronized IManageablePage get(int id)
                {
-                       Serializable serializable = pages.get(id);
-
-                       if (serializable instanceof byte[])
+                       IManageablePage page = null;
+                       
+                       for (int p = 0; p < pages.size(); p++)
                        {
-                               if (serializer == null)
-                               {
-                                       throw new 
IllegalStateException("SessionData#init() was not called");
-                               }
-                               serializable = 
(Serializable)serializer.deserialize((byte[])serializable);
+                               IManageablePage candidate = pages.get(p);
 
-                               pages.put(id, serializable);
+                               if (candidate.getPageId() == id) {
+                                       if (candidate instanceof SerializedPage)
+                                       {
+                                               if (serializer == null)
+                                               {
+                                                       throw new 
IllegalStateException("SessionData#init() was not called");
+                                               }
+                                               candidate = 
(IManageablePage)serializer.deserialize(((SerializedPage)candidate).getData());
+               
+                                               pages.set(id, candidate);
+                                       }
+                                       
+                                       page = candidate;
+                                       break;
+                               }
                        }
 
-                       return (IManageablePage)serializable;
+                       return page;
                }
 
                /**
@@ -250,15 +237,17 @@ public class InSessionPageStore extends 
DelegatingPageStore
                private void writeObject(final ObjectOutputStream output) 
throws IOException
                {
                        // serialize pages if not already
-                       for (Entry<Integer, Serializable> entry : 
pages.entrySet())
+                       for (int p = 0; p < pages.size(); p++)
                        {
-                               if (entry.getValue() instanceof IManageablePage)
+                               IManageablePage page = pages.get(p);
+                               
+                               if ((page instanceof SerializedPage) == false)
                                {
                                        if (serializer == null)
                                        {
                                                throw new 
IllegalStateException("SessionData#init() was not called");
                                        }
-                                       
entry.setValue(serializer.serialize(entry.getValue()));
+                                       pages.set(p,  new 
SerializedPage(page.getPageId(), serializer.serialize(page)));
                                }
                        }
 

http://git-wip-us.apache.org/repos/asf/wicket/blob/a3604f7c/wicket-core/src/main/java/org/apache/wicket/pageStore/SerializedPage.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/pageStore/SerializedPage.java 
b/wicket-core/src/main/java/org/apache/wicket/pageStore/SerializedPage.java
new file mode 100644
index 0000000..86291d9
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/SerializedPage.java
@@ -0,0 +1,74 @@
+/*
+ * 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;
+import org.apache.wicket.util.lang.Args;
+
+/**
+ * A wrapper around a serialized page.
+ * <p>
+ * {@link IPageStore} might choose to use this representation of a page 
internally,
+ * or accept it in {@link IPageStore#addPage(IPageContext, IManageablePage)}.
+ */
+class SerializedPage implements IManageablePage
+{
+
+       private final int pageId;
+
+       private final byte[] data;
+
+       public SerializedPage(int pageId, byte[] data)
+       {
+               this.pageId = pageId;
+               this.data = Args.notNull(data, "data");
+       }
+
+       @Override
+       public boolean isPageStateless()
+       {
+               return false;
+       }
+
+       @Override
+       public int getPageId()
+       {
+               return pageId;
+       }
+
+       public byte[] getData()
+       {
+               return data;
+       }
+       
+       @Override
+       public void detach()
+       {
+       }
+
+       @Override
+       public boolean setFreezePageId(boolean freeze)
+       {
+               return false;
+       }
+       
+       @Override
+       public String toString()
+       {
+               return "[SerializedPage id = " + pageId + "]";
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/wicket/blob/a3604f7c/wicket-core/src/main/java/org/apache/wicket/pageStore/SerializingPageStore.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/pageStore/SerializingPageStore.java
 
b/wicket-core/src/main/java/org/apache/wicket/pageStore/SerializingPageStore.java
new file mode 100644
index 0000000..3b5ac3a
--- /dev/null
+++ 
b/wicket-core/src/main/java/org/apache/wicket/pageStore/SerializingPageStore.java
@@ -0,0 +1,63 @@
+/*
+ * 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;
+import org.apache.wicket.serialize.ISerializer;
+import org.apache.wicket.util.lang.Args;
+
+/**
+ * A store that serializes all pages before delegating and vice versa.
+ */
+public class SerializingPageStore extends DelegatingPageStore
+{
+
+       private ISerializer serializer;
+
+       /**
+        * @param delegate
+        *            store to delegate to
+        * @param serializer
+        *            serializer to use if session gets persisted
+        */
+       public SerializingPageStore(IPageStore delegate, ISerializer serializer)
+       {
+               super(delegate);
+
+               this.serializer = Args.notNull(serializer, "serializer");
+       }
+
+       @Override
+       public IManageablePage getPage(IPageContext context, int id)
+       {
+               IManageablePage page = super.getPage(context, id);
+               if (page instanceof SerializedPage) {
+                       page = 
(IManageablePage)serializer.deserialize(((SerializedPage)page).getData());
+               }
+
+               return super.getPage(context, id);
+       }
+
+       @Override
+       public void addPage(IPageContext context, IManageablePage page)
+       {
+               if (page instanceof SerializedPage == false) {
+                       page = new SerializedPage(page.getPageId(), 
serializer.serialize(page));
+               }
+               super.addPage(context, page);
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/wicket/blob/a3604f7c/wicket-core/src/test/java/org/apache/wicket/versioning/PageVersioningTest.java
----------------------------------------------------------------------
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 4e6420e..3f0e443 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
@@ -26,8 +26,9 @@ import org.apache.wicket.page.PageManager;
 import org.apache.wicket.pageStore.IPageStore;
 import org.apache.wicket.pageStore.InMemoryPageStore;
 import org.apache.wicket.pageStore.InSessionPageStore;
-import org.apache.wicket.pageStore.NoopPageStore;
+import org.apache.wicket.pageStore.SerializingPageStore;
 import org.apache.wicket.protocol.http.WebApplication;
+import org.apache.wicket.serialize.java.JavaSerializer;
 import org.apache.wicket.util.tester.WicketTester;
 import org.junit.After;
 import org.junit.Before;
@@ -59,7 +60,9 @@ public class PageVersioningTest
                        {
                                return () ->
                                {
-                                       final IPageStore store = new 
InSessionPageStore(new NoopPageStore(), Integer.MAX_VALUE);
+                                       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);
                                        return new PageManager(store);
                                };
                        }

Reply via email to