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); }; }
