You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by mg...@apache.org on 2014/03/13 10:06:55 UTC
[2/9] git commit: WICKET-5527 Inefficient
DefaultPageStore.SerializedPagesCache
WICKET-5527 Inefficient DefaultPageStore.SerializedPagesCache
Introduce PerSessionPageStore.
Extract the common logic between DefaultPageStore and PerSessionPageStore into AbstractPageStore.
Extract interface for SecondLevelPageCache implementations
Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/65bd82fe
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/65bd82fe
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/65bd82fe
Branch: refs/heads/master
Commit: 65bd82fe9754d30ed103eba52aa1dc1e07f71bc0
Parents: 8908b8f2
Author: Martin Tzvetanov Grigorov <mg...@apache.org>
Authored: Mon Mar 10 15:20:36 2014 +0200
Committer: Martin Tzvetanov Grigorov <mg...@apache.org>
Committed: Mon Mar 10 15:20:36 2014 +0200
----------------------------------------------------------------------
.../wicket/DefaultPageManagerProvider.java | 2 +
.../apache/wicket/page/AbstractPageManager.java | 23 +-
.../apache/wicket/page/PageStoreManager.java | 2 +-
.../wicket/pageStore/AbstractPageStore.java | 154 +++++++++
.../wicket/pageStore/DefaultPageStore.java | 144 +++-----
.../org/apache/wicket/pageStore/IPageStore.java | 2 +-
.../wicket/pageStore/PerSessionPageStore.java | 337 +++++++++++++++++++
.../wicket/pageStore/SecondLevelPageCache.java | 40 +++
.../wicket/protocol/http/WebApplication.java | 1 -
.../wicket/versioning/InMemoryPageStore.java | 6 +-
10 files changed, 580 insertions(+), 131 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/wicket/blob/65bd82fe/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 4d8adcb..3ce5f8c 100644
--- a/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
+++ b/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
@@ -26,6 +26,7 @@ import org.apache.wicket.pageStore.DefaultPageStore;
import org.apache.wicket.pageStore.DiskDataStore;
import org.apache.wicket.pageStore.IDataStore;
import org.apache.wicket.pageStore.IPageStore;
+import org.apache.wicket.pageStore.PerSessionPageStore;
import org.apache.wicket.serialize.ISerializer;
import org.apache.wicket.settings.StoreSettings;
import org.apache.wicket.util.lang.Bytes;
@@ -71,6 +72,7 @@ public class DefaultPageManagerProvider implements IPageManagerProvider
int inmemoryCacheSize = getStoreSettings().getInmemoryCacheSize();
ISerializer pageSerializer = application.getFrameworkSettings().getSerializer();
return new DefaultPageStore(pageSerializer, dataStore, inmemoryCacheSize);
+// return new PerSessionPageStore(pageSerializer, dataStore, inmemoryCacheSize);
}
protected IDataStore newDataStore()
http://git-wip-us.apache.org/repos/asf/wicket/blob/65bd82fe/wicket-core/src/main/java/org/apache/wicket/page/AbstractPageManager.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/page/AbstractPageManager.java b/wicket-core/src/main/java/org/apache/wicket/page/AbstractPageManager.java
index da259e4..21eb1f1 100644
--- a/wicket-core/src/main/java/org/apache/wicket/page/AbstractPageManager.java
+++ b/wicket-core/src/main/java/org/apache/wicket/page/AbstractPageManager.java
@@ -50,17 +50,9 @@ public abstract class AbstractPageManager implements IPageManager
*/
protected abstract RequestAdapter newRequestAdapter(IPageManagerContext context);
- /**
- *
- * @see org.apache.wicket.page.IPageManager#supportsVersioning()
- */
@Override
public abstract boolean supportsVersioning();
- /**
- *
- * @see org.apache.wicket.page.IPageManager#sessionExpired(java.lang.String)
- */
@Override
public abstract void sessionExpired(String sessionId);
@@ -75,7 +67,6 @@ public abstract class AbstractPageManager implements IPageManager
/**
* @see #newRequestAdapter(IPageManagerContext)
- *
* @return the request adapter
*/
protected RequestAdapter getRequestAdapter()
@@ -89,41 +80,29 @@ public abstract class AbstractPageManager implements IPageManager
return adapter;
}
- /**
- * @see org.apache.wicket.page.IPageManager#commitRequest()
- */
@Override
public void commitRequest()
{
getRequestAdapter().commitRequest();
}
- /**
- * @see org.apache.wicket.page.IPageManager#getPage(int)
- */
@Override
public IManageablePage getPage(int id)
{
IManageablePage page = getRequestAdapter().getPage(id);
if (page != null)
{
- getRequestAdapter().touch(page);
+ touchPage(page);
}
return page;
}
- /**
- * @see org.apache.wicket.page.IPageManager#newSessionCreated()
- */
@Override
public void newSessionCreated()
{
getRequestAdapter().newSessionCreated();
}
- /**
- * @see org.apache.wicket.page.IPageManager#touchPage(org.apache.wicket.page.IManageablePage)
- */
@Override
public void touchPage(IManageablePage page)
{
http://git-wip-us.apache.org/repos/asf/wicket/blob/65bd82fe/wicket-core/src/main/java/org/apache/wicket/page/PageStoreManager.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/page/PageStoreManager.java b/wicket-core/src/main/java/org/apache/wicket/page/PageStoreManager.java
index c13eaee..2149773 100644
--- a/wicket-core/src/main/java/org/apache/wicket/page/PageStoreManager.java
+++ b/wicket-core/src/main/java/org/apache/wicket/page/PageStoreManager.java
@@ -269,7 +269,7 @@ public class PageStoreManager extends AbstractPageManager
{
s.defaultReadObject();
- afterReadObject = new ArrayList<Object>();
+ afterReadObject = new ArrayList<>();
List<Serializable> l = (List<Serializable>)s.readObject();
http://git-wip-us.apache.org/repos/asf/wicket/blob/65bd82fe/wicket-core/src/main/java/org/apache/wicket/pageStore/AbstractPageStore.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/AbstractPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/AbstractPageStore.java
new file mode 100644
index 0000000..16b1cbc
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/AbstractPageStore.java
@@ -0,0 +1,154 @@
+/*
+ * 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 java.io.Serializable;
+
+import org.apache.wicket.page.IManageablePage;
+import org.apache.wicket.serialize.ISerializer;
+import org.apache.wicket.util.lang.Args;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+public abstract class AbstractPageStore implements IPageStore
+{
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractPageStore.class);
+
+ protected final IDataStore dataStore;
+
+ /**
+ * The {@link org.apache.wicket.serialize.ISerializer} that will be used to convert pages from/to byte arrays
+ */
+ protected final ISerializer pageSerializer;
+
+ protected AbstractPageStore(final ISerializer pageSerializer, final IDataStore dataStore)
+ {
+ Args.notNull(pageSerializer, "pageSerializer");
+ Args.notNull(dataStore, "DataStore");
+
+ this.pageSerializer = pageSerializer;
+ this.dataStore = dataStore;
+ }
+
+ @Override
+ public void destroy()
+ {
+ dataStore.destroy();
+ }
+
+ @Override
+ public Serializable prepareForSerialization(final String sessionId, final Serializable page)
+ {
+ if (dataStore.isReplicated())
+ {
+ return null;
+ }
+
+ return page;
+ }
+
+ @Override
+ public Object restoreAfterSerialization(final Serializable serializable)
+ {
+ return serializable;
+ }
+
+ /**
+ * @param sessionId
+ * The id of the http session
+ * @param pageId
+ * The id of page which serialized data should be got
+ * @return page data
+ * @see org.apache.wicket.pageStore.IDataStore#getData(String, int)
+ */
+ protected byte[] getPageData(final String sessionId, final int pageId)
+ {
+ return dataStore.getData(sessionId, pageId);
+ }
+
+ /**
+ * @param sessionId
+ * The id of the http session
+ * @param pageId
+ * The id of page which serialized data should be removed
+ * @see org.apache.wicket.pageStore.IDataStore#removeData(String, int)
+ */
+ protected void removePageData(final String sessionId, final int pageId)
+ {
+ dataStore.removeData(sessionId, pageId);
+ }
+
+ /**
+ * @param sessionId
+ * The id of the http session for which all data should be removed
+ * @see org.apache.wicket.pageStore.IDataStore#removeData(String)
+ */
+ protected void removePageData(final String sessionId)
+ {
+ dataStore.removeData(sessionId);
+ }
+
+ /**
+ * @param sessionId
+ * The id of the http session
+ * @param pageId
+ * The id of the page to store
+ * @param data
+ * The serialized view of the page
+ * @see org.apache.wicket.pageStore.IDataStore#storeData(String, int, byte[])
+ */
+ protected void storePageData(final String sessionId, final int pageId, final byte[] data)
+ {
+ dataStore.storeData(sessionId, pageId, data);
+ }
+
+ /**
+ * Serializes the passed page to byte[]
+ *
+ * @param page
+ * The page to serialize
+ * @return the serialized view of the passed page
+ */
+ protected byte[] serializePage(final IManageablePage page)
+ {
+ Args.notNull(page, "page");
+
+ byte[] data = pageSerializer.serialize(page);
+
+ if (data == null && LOG.isWarnEnabled())
+ {
+ LOG.warn("Page {} cannot be serialized. See previous logs for possible reasons.", page);
+ }
+ return data;
+ }
+
+ /**
+ *
+ * @param data
+ * The serialized view of the page
+ * @return page data deserialized
+ */
+ protected IManageablePage deserializePage(final byte[] data)
+ {
+ Args.notNull(data, "data");
+
+ return (IManageablePage)pageSerializer.deserialize(data);
+ }
+}
http://git-wip-us.apache.org/repos/asf/wicket/blob/65bd82fe/wicket-core/src/main/java/org/apache/wicket/pageStore/DefaultPageStore.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/DefaultPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/DefaultPageStore.java
index 96d4ff0..b27e04f 100644
--- a/wicket-core/src/main/java/org/apache/wicket/pageStore/DefaultPageStore.java
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/DefaultPageStore.java
@@ -34,19 +34,12 @@ import org.slf4j.LoggerFactory;
* direction when loading {@link SerializedPage} from the data store.
*
*/
-public class DefaultPageStore implements IPageStore
+public class DefaultPageStore extends AbstractPageStore
{
private static final Logger LOG = LoggerFactory.getLogger(DefaultPageStore.class);
private final SerializedPagesCache serializedPagesCache;
- private final IDataStore pageDataStore;
-
- /**
- * The {@link ISerializer} that will be used to convert pages from/to byte arrays
- */
- private final ISerializer pageSerializer;
-
/**
* Construct.
*
@@ -61,64 +54,10 @@ public class DefaultPageStore implements IPageStore
public DefaultPageStore(final ISerializer pageSerializer, final IDataStore dataStore,
final int cacheSize)
{
- Args.notNull(pageSerializer, "pageSerializer");
- Args.notNull(dataStore, "DataStore");
-
- this.pageSerializer = pageSerializer;
- pageDataStore = dataStore;
+ super(pageSerializer, dataStore);
serializedPagesCache = new SerializedPagesCache(cacheSize);
}
- /**
- * @see org.apache.wicket.pageStore.IPageStore#destroy()
- */
- @Override
- public void destroy()
- {
- pageDataStore.destroy();
- }
-
- /**
- * @param sessionId
- * @param pageId
- * @return page data
- * @see IDataStore#getData(String, int)
- */
- protected byte[] getPageData(final String sessionId, final int pageId)
- {
- return pageDataStore.getData(sessionId, pageId);
- }
-
- /**
- * @param sessionId
- * @param pageId
- * @see IDataStore#removeData(String, int)
- */
- protected void removePageData(final String sessionId, final int pageId)
- {
- pageDataStore.removeData(sessionId, pageId);
- }
-
- /**
- * @param sessionId
- * @see IDataStore#removeData(String)
- */
- protected void removePageData(final String sessionId)
- {
- pageDataStore.removeData(sessionId);
- }
-
- /**
- * @param sessionId
- * @param pageId
- * @param data
- * @see IDataStore#storeData(String, int, byte[])
- */
- protected void storePageData(final String sessionId, final int pageId, final byte[] data)
- {
- pageDataStore.storeData(sessionId, pageId, data);
- }
-
@Override
public IManageablePage getPage(final String sessionId, final int id)
{
@@ -149,7 +88,7 @@ public class DefaultPageStore implements IPageStore
SerializedPage serialized = serializePage(sessionId, page);
if (serialized != null)
{
- serializedPagesCache.storePage(serialized);
+ serializedPagesCache.storePage(sessionId, page.getPageId(), serialized);
storePageData(sessionId, serialized.getPageId(), serialized.getData());
}
}
@@ -213,38 +152,38 @@ public class DefaultPageStore implements IPageStore
}
@Override
- public Serializable prepareForSerialization(final String sessionId, final Object object)
+ public Serializable prepareForSerialization(final String sessionId, final Serializable page)
{
- if (pageDataStore.isReplicated())
+ if (dataStore.isReplicated())
{
return null;
}
SerializedPage result = null;
- if (object instanceof IManageablePage)
+ if (page instanceof IManageablePage)
{
- IManageablePage page = (IManageablePage)object;
- result = serializedPagesCache.getPage(sessionId, page.getPageId());
+ IManageablePage _page = (IManageablePage)page;
+ result = serializedPagesCache.getPage(sessionId, _page.getPageId());
if (result == null)
{
- result = serializePage(sessionId, page);
+ result = serializePage(sessionId, _page);
if (result != null)
{
- serializedPagesCache.storePage(result);
+ serializedPagesCache.storePage(sessionId, _page.getPageId(), result);
}
}
}
- else if (object instanceof SerializedPage)
+ else if (page instanceof SerializedPage)
{
- SerializedPage page = (SerializedPage)object;
- if (page.getData() == null)
+ SerializedPage _page = (SerializedPage)page;
+ if (_page.getData() == null)
{
- result = restoreStrippedSerializedPage(page);
+ result = restoreStrippedSerializedPage(_page);
}
else
{
- result = page;
+ result = _page;
}
}
@@ -252,7 +191,7 @@ public class DefaultPageStore implements IPageStore
{
return result;
}
- return (Serializable)object;
+ return page;
}
/**
@@ -372,7 +311,7 @@ public class DefaultPageStore implements IPageStore
SerializedPage serializedPage = null;
- byte[] data = pageSerializer.serialize(page);
+ byte[] data = serializePage(page);
if (data != null)
{
@@ -386,17 +325,6 @@ public class DefaultPageStore implements IPageStore
}
/**
- *
- * @param data
- * @return page data deserialized
- */
- protected IManageablePage deserializePage(final byte[] data)
- {
- IManageablePage page = (IManageablePage)pageSerializer.deserialize(data);
- return page;
- }
-
- /**
* Cache that stores serialized pages. This is important to make sure that a single page is not
* serialized twice or more when not necessary.
* <p>
@@ -406,7 +334,7 @@ public class DefaultPageStore implements IPageStore
*
* @author Matej Knopp
*/
- static class SerializedPagesCache
+ static class SerializedPagesCache implements SecondLevelPageCache<String, Integer, SerializedPage>
{
private final int size;
@@ -426,20 +354,22 @@ public class DefaultPageStore implements IPageStore
/**
*
* @param sessionId
- * @param id
+ * @param pageId
* @return the removed {@link SerializedPage} or <code>null</code> - otherwise
*/
- public SerializedPage removePage(final String sessionId, final int id)
+ @Override
+ public SerializedPage removePage(final String sessionId, final Integer pageId)
{
- Args.notNull(sessionId, "sessionId");
-
if (size > 0)
{
+ Args.notNull(sessionId, "sessionId");
+ Args.notNull(pageId, "pageId");
+
for (Iterator<SoftReference<SerializedPage>> i = cache.iterator(); i.hasNext();)
{
SoftReference<SerializedPage> ref = i.next();
SerializedPage entry = ref.get();
- if (entry != null && entry.getPageId() == id &&
+ if (entry != null && entry.getPageId() == pageId &&
entry.getSessionId().equals(sessionId))
{
i.remove();
@@ -456,12 +386,13 @@ public class DefaultPageStore implements IPageStore
*
* @param sessionId
*/
+ @Override
public void removePages(String sessionId)
{
- Args.notNull(sessionId, "sessionId");
-
if (size > 0)
{
+ Args.notNull(sessionId, "sessionId");
+
for (Iterator<SoftReference<SerializedPage>> i = cache.iterator(); i.hasNext();)
{
SoftReference<SerializedPage> ref = i.next();
@@ -483,13 +414,15 @@ public class DefaultPageStore implements IPageStore
* @param pageId
* @return the found serialized page or <code>null</code> when not found
*/
- public SerializedPage getPage(String sessionId, int pageId)
+ @Override
+ public SerializedPage getPage(String sessionId, Integer pageId)
{
- Args.notNull(sessionId, "sessionId");
-
SerializedPage result = null;
if (size > 0)
{
+ Args.notNull(sessionId, "sessionId");
+ Args.notNull(pageId, "pageId");
+
for (Iterator<SoftReference<SerializedPage>> i = cache.iterator(); i.hasNext();)
{
SoftReference<SerializedPage> ref = i.next();
@@ -506,7 +439,7 @@ public class DefaultPageStore implements IPageStore
if (result != null)
{
// move to top
- storePage(result);
+ storePage(sessionId, pageId, result);
}
}
return result;
@@ -518,10 +451,15 @@ public class DefaultPageStore implements IPageStore
* @param page
* the data to serialize (page id, session id, bytes)
*/
- void storePage(SerializedPage page)
+ @Override
+ public void storePage(String sessionId, Integer pageId, SerializedPage page)
{
if (size > 0)
{
+ Args.notNull(sessionId, "sessionId");
+ Args.notNull(pageId, "pageId");
+ Args.notNull(page, "page");
+
for (Iterator<SoftReference<SerializedPage>> i = cache.iterator(); i.hasNext();)
{
SoftReference<SerializedPage> r = i.next();
@@ -534,7 +472,7 @@ public class DefaultPageStore implements IPageStore
}
cache.add(new SoftReference<>(page));
- if (cache.size() > size)
+ while (cache.size() > size)
{
cache.remove(0);
}
http://git-wip-us.apache.org/repos/asf/wicket/blob/65bd82fe/wicket-core/src/main/java/org/apache/wicket/pageStore/IPageStore.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/IPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/IPageStore.java
index 5fe3cf6..470536a 100644
--- a/wicket-core/src/main/java/org/apache/wicket/pageStore/IPageStore.java
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/IPageStore.java
@@ -84,7 +84,7 @@ public interface IPageStore
* @param page
* @return The Page itself or a SerializedContainer for that page
*/
- Serializable prepareForSerialization(String sessionId, Object page);
+ Serializable prepareForSerialization(String sessionId, Serializable page);
/**
* This method should restore the serialized page to intermediate object that can be converted
http://git-wip-us.apache.org/repos/asf/wicket/blob/65bd82fe/wicket-core/src/main/java/org/apache/wicket/pageStore/PerSessionPageStore.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/PerSessionPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/PerSessionPageStore.java
new file mode 100644
index 0000000..ac57ab9
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/PerSessionPageStore.java
@@ -0,0 +1,337 @@
+/*
+ * 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 java.lang.ref.SoftReference;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentSkipListMap;
+
+import org.apache.wicket.page.IManageablePage;
+import org.apache.wicket.serialize.ISerializer;
+import org.apache.wicket.util.lang.Args;
+import org.apache.wicket.util.lang.Objects;
+import org.apache.wicket.util.time.Time;
+
+/**
+ *
+ */
+public class PerSessionPageStore extends AbstractPageStore
+{
+ private final SecondLevelPageCache<String, Integer, IManageablePage> pagesCache;
+
+ /**
+ * Construct.
+ *
+ * @param pageSerializer
+ * the {@link org.apache.wicket.serialize.ISerializer} that will be used to convert pages from/to byte arrays
+ * @param dataStore
+ * the {@link org.apache.wicket.pageStore.IDataStore} that actually stores the pages
+ * @param cacheSize
+ * the number of pages to cache in memory before passing them to
+ * {@link org.apache.wicket.pageStore.IDataStore#storeData(String, int, byte[])}
+ */
+ public PerSessionPageStore(final ISerializer pageSerializer, final IDataStore dataStore,
+ final int cacheSize)
+ {
+ super(pageSerializer, dataStore);
+ this.pagesCache = new PagesCache(cacheSize);
+ }
+
+ @Override
+ public IManageablePage getPage(final String sessionId, final int id)
+ {
+ IManageablePage fromCache = pagesCache.getPage(sessionId, id);
+ if (fromCache != null)
+ {
+ return fromCache;
+ }
+
+ byte[] data = getPageData(sessionId, id);
+ if (data != null)
+ {
+ return deserializePage(data);
+ }
+ return null;
+ }
+
+ @Override
+ public void removePage(final String sessionId, final int id)
+ {
+ pagesCache.removePage(sessionId, id);
+ removePageData(sessionId, id);
+ }
+
+ @Override
+ public void storePage(final String sessionId, final IManageablePage page)
+ {
+ byte[] data = serializePage(page);
+ if (data != null)
+ {
+ pagesCache.storePage(sessionId, page.getPageId(), page);
+ storePageData(sessionId, page.getPageId(), data);
+ }
+ }
+
+ @Override
+ public void unbind(final String sessionId)
+ {
+ removePageData(sessionId);
+ pagesCache.removePages(sessionId);
+ }
+
+ @Override
+ public IManageablePage convertToPage(final Object object)
+ {
+ if (object == null)
+ {
+ return null;
+ }
+ else if (object instanceof IManageablePage)
+ {
+ return (IManageablePage)object;
+ }
+
+ String type = object.getClass().getName();
+ throw new IllegalArgumentException("Unknown object type: " + type);
+ }
+
+ /**
+ */
+ protected static class PagesCache implements SecondLevelPageCache<String, Integer, IManageablePage>
+ {
+ /**
+ * Helper class used to compare the page entries in the cache by their
+ * access time
+ */
+ private static class PageValue
+ {
+ /**
+ * The id of the cached page
+ */
+ private final int pageId;
+
+ /**
+ * The last time this page has been used/accessed.
+ */
+ private Time accessTime;
+
+ private PageValue(IManageablePage page)
+ {
+ this(page.getPageId());
+ }
+
+ private PageValue(int pageId)
+ {
+ this.pageId = pageId;
+ this.accessTime = Time.now();
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ PageValue pageValue = (PageValue) o;
+
+ return pageId == pageValue.pageId;
+
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return pageId;
+ }
+ }
+
+ private static class PageComparator implements Comparator<PageValue>
+ {
+ @Override
+ public int compare(PageValue p1, PageValue p2)
+ {
+ return Objects.compareWithConversion(p1.accessTime, p2.accessTime);
+ }
+ }
+
+ private final int maxEntriesPerSession;
+
+ private final ConcurrentSkipListMap<String, SoftReference<ConcurrentSkipListMap<PageValue, IManageablePage>>> cache;
+
+ /**
+ * Constructor.
+ *
+ * @param maxEntriesPerSession
+ * The number of cache entries per session
+ */
+ public PagesCache(final int maxEntriesPerSession)
+ {
+ this.maxEntriesPerSession = maxEntriesPerSession;
+ cache = new ConcurrentSkipListMap<>();
+ }
+
+ /**
+ *
+ * @param sessionId
+ * The id of the http session
+ * @param pageId
+ * The id of the page to remove from the cache
+ * @return the removed {@link org.apache.wicket.page.IManageablePage} or <code>null</code> - otherwise
+ */
+ @Override
+ public IManageablePage removePage(final String sessionId, final Integer pageId)
+ {
+ IManageablePage result = null;
+
+ if (maxEntriesPerSession > 0)
+ {
+ Args.notNull(sessionId, "sessionId");
+ Args.notNull(pageId, "pageId");
+
+ SoftReference<ConcurrentSkipListMap<PageValue, IManageablePage>> pagesPerSession = cache.get(sessionId);
+ if (pagesPerSession != null)
+ {
+ ConcurrentMap<PageValue, IManageablePage> pages = pagesPerSession.get();
+ if (pages != null)
+ {
+ PageValue pv = new PageValue(pageId);
+ IManageablePage page = pages.remove(pv);
+ if (page != null)
+ {
+ result = page;
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Removes all {@link org.apache.wicket.page.IManageablePage}s for the session
+ * with <code>sessionId</code> from the cache.
+ *
+ * @param sessionId
+ * The id of the expired http session
+ */
+ @Override
+ public void removePages(String sessionId)
+ {
+ Args.notNull(sessionId, "sessionId");
+
+ if (maxEntriesPerSession > 0)
+ {
+ cache.remove(sessionId);
+ }
+ }
+
+ /**
+ * Returns a {@link org.apache.wicket.page.IManageablePage} by looking it up by <code>sessionId</code> and
+ * <code>pageId</code>. If there is a match then it is <i>touched</i>, i.e. it is moved at
+ * the top of the cache.
+ *
+ * @param sessionId
+ * The id of the http session
+ * @param pageId
+ * The id of the page to find
+ * @return the found serialized page or <code>null</code> when not found
+ */
+ @Override
+ public IManageablePage getPage(String sessionId, Integer pageId)
+ {
+ IManageablePage result = null;
+
+ if (maxEntriesPerSession > 0)
+ {
+ Args.notNull(sessionId, "sessionId");
+ Args.notNull(pageId, "pageId");
+
+ SoftReference<ConcurrentSkipListMap<PageValue, IManageablePage>> pagesPerSession = cache.get(sessionId);
+ if (pagesPerSession != null)
+ {
+ ConcurrentSkipListMap<PageValue, IManageablePage> pages = pagesPerSession.get();
+ if (pages != null)
+ {
+ PageValue pv = new PageValue(pageId);
+ Map.Entry<PageValue, IManageablePage> entry = pages.ceilingEntry(pv);
+
+ if (entry != null)
+ {
+ // touch the entry
+ entry.getKey().accessTime = Time.now();
+ result = entry.getValue();
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Store the serialized page in cache
+ *
+ * @param page
+ * the data to serialize (page id, session id, bytes)
+ */
+ @Override
+ public void storePage(String sessionId, Integer pageId, IManageablePage page)
+ {
+ if (maxEntriesPerSession > 0)
+ {
+ Args.notNull(sessionId, "sessionId");
+ Args.notNull(pageId, "pageId");
+
+ SoftReference<ConcurrentSkipListMap<PageValue, IManageablePage>> pagesPerSession = cache.get(sessionId);
+ if (pagesPerSession == null)
+ {
+ ConcurrentSkipListMap<PageValue, IManageablePage> pages = new ConcurrentSkipListMap<>(new PageComparator());
+ pagesPerSession = new SoftReference<>(pages);
+ SoftReference<ConcurrentSkipListMap<PageValue, IManageablePage>> old = cache.putIfAbsent(sessionId, pagesPerSession);
+ if (old != null)
+ {
+ pagesPerSession = old;
+ }
+ }
+
+ ConcurrentSkipListMap<PageValue, IManageablePage> pages = pagesPerSession.get();
+ if (pages == null)
+ {
+ pages = new ConcurrentSkipListMap<>();
+ pagesPerSession = new SoftReference<>(pages);
+ SoftReference<ConcurrentSkipListMap<PageValue, IManageablePage>> old = cache.putIfAbsent(sessionId, pagesPerSession);
+ if (old != null)
+ {
+ pages = old.get();
+ }
+ }
+
+ if (pages != null)
+ {
+ while (pages.size() > maxEntriesPerSession)
+ {
+ pages.pollFirstEntry();
+ }
+
+ PageValue pv = new PageValue(page);
+ pages.put(pv, page);
+ }
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/wicket/blob/65bd82fe/wicket-core/src/main/java/org/apache/wicket/pageStore/SecondLevelPageCache.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/SecondLevelPageCache.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/SecondLevelPageCache.java
new file mode 100644
index 0000000..656827e
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/SecondLevelPageCache.java
@@ -0,0 +1,40 @@
+/*
+ * 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;
+
+/**
+ * An application scoped cache that holds the last N used pages in the application.
+ * Acts as a second level cache between the Http Session (first level) and the
+ * disk (third level cache).
+ *
+ * @param <S>
+ * The type of the session identifier
+ * @param <PI>
+ * The type of the page identifier
+ * @param <P>
+ * The type of the stored page
+ */
+public interface SecondLevelPageCache<S, PI, P>
+{
+ P removePage(S session, PI pageId);
+
+ void removePages(S session);
+
+ P getPage(S session, PI pageId);
+
+ void storePage(S session, PI pageId, P page);
+}
http://git-wip-us.apache.org/repos/asf/wicket/blob/65bd82fe/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java b/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
index 6c30bd1..988243a 100644
--- a/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
+++ b/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
@@ -66,7 +66,6 @@ import org.apache.wicket.request.resource.CssResourceReference;
import org.apache.wicket.request.resource.JavaScriptResourceReference;
import org.apache.wicket.request.resource.ResourceReference;
import org.apache.wicket.resource.bundles.ReplacementResourceBundleReference;
-import org.apache.wicket.resource.bundles.ResourceBundleReference;
import org.apache.wicket.session.HttpSessionStore;
import org.apache.wicket.session.ISessionStore;
import org.apache.wicket.util.IContextProvider;
http://git-wip-us.apache.org/repos/asf/wicket/blob/65bd82fe/wicket-core/src/test/java/org/apache/wicket/versioning/InMemoryPageStore.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/versioning/InMemoryPageStore.java b/wicket-core/src/test/java/org/apache/wicket/versioning/InMemoryPageStore.java
index ca1399a..f69a918 100644
--- a/wicket-core/src/test/java/org/apache/wicket/versioning/InMemoryPageStore.java
+++ b/wicket-core/src/test/java/org/apache/wicket/versioning/InMemoryPageStore.java
@@ -40,7 +40,7 @@ public class InMemoryPageStore implements IDataStore
*/
public InMemoryPageStore()
{
- store = new ConcurrentHashMap<String, Map<Integer, byte[]>> ();
+ store = new ConcurrentHashMap<> ();
}
@Override
@@ -97,7 +97,7 @@ public class InMemoryPageStore implements IDataStore
Map<Integer, byte[]> sessionPages = store.get(sessionId);
if (sessionPages == null)
{
- sessionPages = new ConcurrentHashMap<Integer, byte[]>();
+ sessionPages = new ConcurrentHashMap<>();
Map<Integer, byte[]> tmpSessionPages = store.putIfAbsent(sessionId, sessionPages);
if (tmpSessionPages != null)
{
@@ -123,4 +123,4 @@ public class InMemoryPageStore implements IDataStore
return false;
}
-}
\ No newline at end of file
+}