You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by sv...@apache.org on 2018/07/02 21:25:22 UTC
[3/5] wicket git commit: WICKET-6563 new IPageStore implementation
http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/IPersistedPage.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/IPersistedPage.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/IPersistedPage.java
new file mode 100644
index 0000000..8a03507
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/IPersistedPage.java
@@ -0,0 +1,44 @@
+/*
+ * 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.util.lang.Bytes;
+
+/**
+ * Information about a persisted page in an {@link IPersistentPageStore}.
+ *
+ * @see IPersistentPageStore#getPersistentPages(String, int)
+ */
+public interface IPersistedPage extends Serializable
+{
+ /**
+ * Id of page.
+ */
+ int getPageId();
+
+ /**
+ * Size of page.
+ */
+ Bytes getPageSize();
+
+ /**
+ * Type of page.
+ */
+ String getPageType();
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/IPersistentPageStore.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/IPersistentPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/IPersistentPageStore.java
new file mode 100644
index 0000000..b42746d
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/IPersistentPageStore.java
@@ -0,0 +1,51 @@
+/*
+ * 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.util.List;
+import java.util.Set;
+
+import org.apache.wicket.util.lang.Bytes;
+
+/**
+ * A store that can provide information about stored pages.
+ */
+public interface IPersistentPageStore extends IPageStore
+{
+
+ /**
+ * Get the identifier for pages stored for the given context.
+ */
+ String getSessionIdentifier(IPageContext context);
+
+ /**
+ * Get the identifiers for all pages stored in all contexts.
+ */
+ Set<String> getSessionIdentifiers();
+
+ /**
+ * Get information about all persisted pages with the given session identifier.
+ */
+ List<IPersistedPage> getPersistentPages(String sessionIdentifier);
+
+ /**
+ * Get total size of all stored pages.
+ *
+ * @return
+ */
+ Bytes getTotalSize();
+}
http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/InMemoryPageStore.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/InMemoryPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/InMemoryPageStore.java
new file mode 100644
index 0000000..fc11901
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/InMemoryPageStore.java
@@ -0,0 +1,352 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionBindingListener;
+
+import org.apache.wicket.Application;
+import org.apache.wicket.Session;
+import org.apache.wicket.core.util.lang.WicketObjects;
+import org.apache.wicket.page.IManageablePage;
+import org.apache.wicket.util.lang.Args;
+import org.apache.wicket.util.lang.Bytes;
+
+/**
+ * A storage of pages in memory.
+ */
+public class InMemoryPageStore implements IPersistentPageStore
+{
+
+ /**
+ * A registry of all page instances.
+ */
+ private static final ConcurrentMap<String, InMemoryPageStore> IN_MEMORY_STORES = new ConcurrentHashMap<>();
+
+ private static final String KEY = "wicket:InMemoryPageStore";
+
+ private final Map<String, MemoryData> datas = new ConcurrentHashMap<>();
+
+ private String applicationName;
+
+ private int maxPages;
+
+ /**
+ * @param applicationName
+ * {@link Application#getName()}
+ * @param maxPages
+ * max pages per session
+ */
+ public InMemoryPageStore(String applicationName, int maxPages)
+ {
+ this.applicationName = Args.notNull(applicationName, "applicationName");
+ this.maxPages = maxPages;
+
+ IN_MEMORY_STORES.put(applicationName, this);
+ }
+
+ /**
+ *
+ *
+ * @return <code>true</code> always
+ */
+ @Override
+ public boolean canBeAsynchronous(IPageContext context)
+ {
+ // session attribute must be added here *before* any asynchronous calls
+ // when session is no longer available
+ getSessionAttribute(context, true);
+
+ return true;
+ }
+
+ protected SessionAttribute getSessionAttribute(IPageContext context, boolean create)
+ {
+ context.bind();
+
+ SessionAttribute attribute = context.getSessionAttribute(KEY);
+ if (attribute == null && create)
+ {
+ attribute = new SessionAttribute(applicationName, context.getSessionId());
+ context.setSessionAttribute(KEY, attribute);
+ }
+ return attribute;
+ }
+
+ @Override
+ public void destroy()
+ {
+ datas.clear();
+
+ IN_MEMORY_STORES.remove(applicationName);
+ }
+
+ @Override
+ public IManageablePage getPage(IPageContext context, int id)
+ {
+ MemoryData data = getMemoryData(context, false);
+ if (data == null)
+ {
+ return null;
+ }
+
+ return data.get(id);
+ }
+
+ @Override
+ public void removePage(IPageContext context, final IManageablePage page)
+ {
+ MemoryData data = getMemoryData(context, false);
+
+ if (data != null)
+ {
+ synchronized (data)
+ {
+ data.remove(page);
+ }
+ }
+ }
+
+ @Override
+ public void removeAllPages(IPageContext context)
+ {
+ MemoryData data = getMemoryData(context, false);
+
+ if (data != null)
+ {
+ synchronized (data)
+ {
+ data.removeAll();
+ }
+ }
+ }
+
+ @Override
+ public void addPage(IPageContext context, IManageablePage page)
+ {
+ MemoryData data = getMemoryData(context, true);
+
+ data.add(page, maxPages);
+ }
+
+ @Override
+ public String getSessionIdentifier(IPageContext context)
+ {
+ return context.getSessionId();
+ }
+
+ @Override
+ public Set<String> getSessionIdentifiers()
+ {
+ return datas.keySet();
+ }
+
+ @Override
+ public List<IPersistedPage> getPersistentPages(String sessionIdentifier)
+ {
+ MemoryData data = datas.get(sessionIdentifier);
+ if (data == null)
+ {
+ return new ArrayList<>();
+ }
+
+ synchronized (data)
+ {
+ return StreamSupport.stream(data.spliterator(), false)
+ .map(page -> new MermoryPersistedPage(page, getSize(page)))
+ .collect(Collectors.toList());
+ }
+ }
+
+ @Override
+ public Bytes getTotalSize()
+ {
+ int size = 0;
+
+ for (MemoryData data : datas.values())
+ {
+ synchronized (data)
+ {
+ for (IManageablePage page : data)
+ {
+ size += getSize(page);
+ }
+ }
+ }
+
+ return Bytes.bytes(size);
+ }
+
+ protected long getSize(IManageablePage page)
+ {
+ return WicketObjects.sizeof(page);
+ }
+
+ private MemoryData getMemoryData(IPageContext context, boolean create)
+ {
+ SessionAttribute attribute = getSessionAttribute(context, create);
+
+ if (!create)
+ {
+ if (attribute == null) {
+ return null;
+ } else {
+ return datas.get(attribute.identifier);
+ }
+ }
+
+ MemoryData data = new MemoryData();
+ MemoryData existing = datas.putIfAbsent(attribute.identifier, data);
+ return existing != null ? existing : data;
+ }
+
+ private void removeMemoryData(String identifier)
+ {
+ datas.remove(identifier);
+ }
+
+ /**
+ * Data kept in memory.
+ */
+ static class MemoryData implements Iterable<IManageablePage>
+ {
+ private LinkedHashMap<Integer, IManageablePage> pages = new LinkedHashMap<>();
+
+ @Override
+ public Iterator<IManageablePage> iterator()
+ {
+ return pages.values().iterator();
+ }
+
+ public synchronized void add(IManageablePage page, int maxPages)
+ {
+ pages.remove(page.getPageId());
+ pages.put(page.getPageId(), page);
+
+ Iterator<IManageablePage> iterator = pages.values().iterator();
+ int size = pages.size();
+ while (size > maxPages)
+ {
+ iterator.next();
+
+ iterator.remove();
+ size--;
+ }
+ }
+
+ public void remove(IManageablePage page)
+ {
+ pages.remove(page.getPageId());
+ }
+
+ public void removeAll()
+ {
+ pages.clear();
+ }
+
+ public IManageablePage get(int id)
+ {
+ IManageablePage page = pages.get(id);
+
+ return page;
+ }
+ }
+
+ /**
+ * Attribute held in session.
+ */
+ static class SessionAttribute implements Serializable, HttpSessionBindingListener
+ {
+
+ private final String applicationName;
+
+ /**
+ * The identifier of the session, must not be equal to {@link Session#getId()}, e.g. when
+ * the container changes the id after authorization.
+ */
+ public final String identifier;
+
+ public SessionAttribute(String applicationName, String sessionIdentifier)
+ {
+ this.applicationName = Args.notNull(applicationName, "applicationName");
+ this.identifier = Args.notNull(sessionIdentifier, "sessionIdentifier");
+ }
+
+
+ @Override
+ public void valueBound(HttpSessionBindingEvent event)
+ {
+ }
+
+ @Override
+ public void valueUnbound(HttpSessionBindingEvent event)
+ {
+ InMemoryPageStore store = IN_MEMORY_STORES.get(applicationName);
+ if (store != null)
+ {
+ store.removeMemoryData(identifier);
+ }
+ }
+ }
+
+ private static class MermoryPersistedPage implements IPersistedPage
+ {
+
+ private final int id;
+
+ private final String type;
+
+ private final long size;
+
+ public MermoryPersistedPage(IManageablePage page, long size)
+ {
+ this.id = page.getPageId();
+ this.type = page.getClass().getName();
+ this.size = size;
+ }
+
+ @Override
+ public int getPageId()
+ {
+ return id;
+ }
+
+ @Override
+ public String getPageType()
+ {
+ return type;
+ }
+
+ @Override
+ public Bytes getPageSize()
+ {
+ return Bytes.bytes(size);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/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
new file mode 100644
index 0000000..3914464
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/InSessionPageStore.java
@@ -0,0 +1,268 @@
+/*
+ * 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.IOException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map.Entry;
+
+import javax.servlet.http.HttpSession;
+
+import org.apache.wicket.MetaDataKey;
+import org.apache.wicket.Session;
+import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.page.IManageablePage;
+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.
+ */
+public class InSessionPageStore extends DelegatingPageStore
+{
+
+ private static final MetaDataKey<SessionData> KEY = new MetaDataKey<SessionData>()
+ {
+ private static final long serialVersionUID = 1L;
+ };
+
+ private ISerializer serializer;
+
+ private int maxPages;
+
+ private boolean delegateAll = false;
+
+ /**
+ * Use this constructor, if sessions are never serialized.
+ *
+ * @param delegate
+ * store to delegate to
+ * @param maxPages
+ * maximum pages to keep in session
+ */
+ public InSessionPageStore(IPageStore delegate, int maxPages)
+ {
+ this(delegate, new ISerializer()
+ {
+ @Override
+ public byte[] serialize(Object object)
+ {
+ throw new WicketRuntimeException("InSessionPageStore not configured for serialization");
+ }
+
+ @Override
+ public Object deserialize(byte[] data)
+ {
+ throw new WicketRuntimeException("InSessionPageStore not configured for serialization");
+ }
+ }, maxPages);
+ }
+
+ /**
+ * @param delegate
+ * store to delegate to
+ * @param serializer
+ * serializer to use if session gets persisted
+ * @param maxPages
+ * maximum pages to keep in session
+ */
+ public InSessionPageStore(IPageStore delegate, ISerializer serializer, int maxPages)
+ {
+ super(delegate);
+
+ this.serializer = Args.notNull(serializer, "serializer");
+
+ 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)
+ {
+ IManageablePage page = getSessionData(context).get(id);
+ if (page != null)
+ {
+ return page;
+ }
+
+ return super.getPage(context, id);
+ }
+
+ @Override
+ public void addPage(IPageContext context, IManageablePage page)
+ {
+ SessionData data = getSessionData(context);
+
+ data.addAndDelegate(context, page, maxPages, delegateAll, getDelegate());
+ }
+
+ @Override
+ public void removePage(IPageContext context, IManageablePage page)
+ {
+ getSessionData(context).remove(page);
+
+ super.removePage(context, page);
+ }
+
+ @Override
+ public void removeAllPages(IPageContext context)
+ {
+ getSessionData(context).removeAll();
+
+ super.removeAllPages(context);
+ }
+
+ private SessionData getSessionData(IPageContext context)
+ {
+ SessionData data = context.getSessionData(KEY);
+ if (data == null)
+ {
+ context.bind();
+ data = new SessionData();
+
+ context.setSessionData(KEY, data);
+ }
+
+ // data might be deserialized so initialize again
+ data.init(serializer);
+
+ return data;
+ }
+
+ /**
+ * Data kept in the {@link Session}, might get serialized along with its containing
+ * {@link HttpSession}.
+ */
+ static class SessionData implements Serializable
+ {
+
+ transient ISerializer serializer;
+
+ /**
+ * Pages, may partly be serialized.
+ */
+ private LinkedHashMap<Integer, Serializable> pages = new LinkedHashMap<>();
+
+ /**
+ * This method <em>must</em> be called each time it is retrieved from the session: <br/>
+ * After deserializing from persisted session the serializer is no longer referenced and all
+ * contained pages are in a serialized state.
+ */
+ public void init(ISerializer serializer)
+ {
+ this.serializer = Args.notNull(serializer, "serializer");
+ }
+
+ public synchronized void addAndDelegate(IPageContext context, IManageablePage page,
+ int maxPages, boolean delegateAll, IPageStore delegate)
+ {
+ pages.remove(page.getPageId());
+ pages.put(page.getPageId(), 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
+ {
+ // 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);
+ }
+ }
+ }
+
+ public synchronized void remove(IManageablePage page)
+ {
+ pages.remove(page.getPageId());
+ }
+
+ public synchronized void removeAll()
+ {
+ pages.clear();
+ }
+
+ public synchronized IManageablePage get(int id)
+ {
+ Serializable serializable = pages.get(id);
+
+ if (serializable instanceof byte[])
+ {
+ if (serializer == null)
+ {
+ throw new IllegalStateException("SessionData#init() was not called");
+ }
+ serializable = (Serializable)serializer.deserialize((byte[])serializable);
+
+ pages.put(id, serializable);
+ }
+
+ return (IManageablePage)serializable;
+ }
+
+ /**
+ * Serialize pages before writing to output.
+ */
+ private void writeObject(final ObjectOutputStream output) throws IOException
+ {
+ // serialize pages if not already
+ for (Entry<Integer, Serializable> entry : pages.entrySet())
+ {
+ if (entry.getValue() instanceof IManageablePage)
+ {
+ if (serializer == null)
+ {
+ throw new IllegalStateException("SessionData#init() was not called");
+ }
+ entry.setValue(serializer.serialize(entry.getValue()));
+ }
+ }
+
+ output.defaultWriteObject();
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/NoopPageStore.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/NoopPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/NoopPageStore.java
new file mode 100644
index 0000000..846c858
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/NoopPageStore.java
@@ -0,0 +1,53 @@
+/*
+ * 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 non-storage of pages.
+ */
+public class NoopPageStore implements IPageStore
+{
+
+ @Override
+ public boolean canBeAsynchronous(IPageContext context)
+ {
+ return true;
+ }
+
+ @Override
+ public void addPage(IPageContext context, IManageablePage page)
+ {
+ }
+
+ @Override
+ public void removePage(IPageContext context, IManageablePage page)
+ {
+ }
+
+ @Override
+ public void removeAllPages(IPageContext context)
+ {
+ }
+
+ @Override
+ public IManageablePage getPage(IPageContext context, int id)
+ {
+ return null;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/PageWindowManager.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/PageWindowManager.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/PageWindowManager.java
deleted file mode 100644
index f194710..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/pageStore/PageWindowManager.java
+++ /dev/null
@@ -1,506 +0,0 @@
-/*
- * 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 java.util.ArrayList;
-import java.util.List;
-
-import org.apache.wicket.util.collections.IntHashMap;
-
-/**
- * Manages positions and size of serialized pages in the pagemap file.
- * <p>
- * The pages are stored inside the file in a cyclic way. Newer pages are placed after older ones,
- * until the maximum file size is reached. After that, the next page is stored in the beginning of
- * the file.
- *
- * @author Matej Knopp
- */
-public class PageWindowManager implements Serializable
-{
- private static final long serialVersionUID = 1L;
-
- /**
- * Contains information about a page inside the file.
- *
- * @author Matej Knopp
- */
- private static class PageWindowInternal implements Serializable
- {
- private static final long serialVersionUID = 1L;
-
- /** id of page or -1 if the window is empty */
- private int pageId;
-
- /** offset in the file where the serialized page data begins */
- private int filePartOffset;
-
- /** size of serialized page data */
- private int filePartSize;
- }
-
- /** list of PageWindowInternal objects */
- private final List<PageWindowInternal> windows = new ArrayList<PageWindowInternal>();
-
- /**
- * map from page id to list of pagewindow indices (referring to the windows list) - to improve
- * searching speed the index must be cleaned when the instances in the windows list change their
- * indexes (e.g. items are shifted on page window removal)
- */
- private IntHashMap<Integer> idToWindowIndex = null;
-
- /**
- * Inversed index of #idToWindowIndex
- */
- private IntHashMap<Integer> windowIndexToPageId = null;
-
- /** index of last added page */
- private int indexPointer = -1;
-
- private int totalSize = 0;
-
- /**
- * Maximum page size. After this size is exceeded, the pages will be saved starting at the
- * beginning of file.
- */
- private final long maxSize;
-
- /**
- *
- * @param pageId
- * @param windowIndex
- */
- private void putWindowIndex(int pageId, int windowIndex)
- {
- if (idToWindowIndex != null && pageId != -1 && windowIndex != -1)
- {
- Integer oldPageId = windowIndexToPageId.remove(windowIndex);
- if (oldPageId != null)
- {
- idToWindowIndex.remove(oldPageId);
- }
- idToWindowIndex.put(pageId, windowIndex);
- windowIndexToPageId.put(windowIndex, pageId);
- }
- }
-
- /**
- *
- * @param pageId
- */
- private void removeWindowIndex(int pageId)
- {
- Integer windowIndex = idToWindowIndex.remove(pageId);
- if (windowIndex != null)
- {
- windowIndexToPageId.remove(windowIndex);
- }
- }
-
- /**
- *
- */
- private void rebuildIndices()
- {
- idToWindowIndex = null;
- idToWindowIndex = new IntHashMap<Integer>();
- windowIndexToPageId = null;
- windowIndexToPageId = new IntHashMap<Integer>();
- for (int i = 0; i < windows.size(); ++i)
- {
- PageWindowInternal window = windows.get(i);
- putWindowIndex(window.pageId, i);
- }
- }
-
- /**
- * Returns the index of the given page in the {@link #windows} list.
- *
- * @param pageId
- * @return window index
- */
- private int getWindowIndex(int pageId)
- {
- if (idToWindowIndex == null)
- {
- rebuildIndices();
- }
-
- Integer result = idToWindowIndex.get(pageId);
- return result != null ? result : -1;
- }
-
- /**
- * Increments the {@link #indexPointer}. If the maximum file size has been reached, the
- * {@link #indexPointer} is set to 0.
- *
- * @return new index pointer
- */
- private int incrementIndexPointer()
- {
- if ((maxSize > 0) && (totalSize >= maxSize) && (indexPointer == windows.size() - 1))
- {
- indexPointer = 0;
- }
- else
- {
- ++indexPointer;
- }
- return indexPointer;
- }
-
- /**
- * Returns the offset in file of the window on given index. The offset is counted by getting the
- * previous page offset and adding the previous page size to it.
- *
- * @param index
- * @return window file offset
- */
- private int getWindowFileOffset(int index)
- {
- if (index > 0)
- {
- PageWindowInternal window = windows.get(index - 1);
- return window.filePartOffset + window.filePartSize;
- }
- return 0;
- }
-
- /**
- * Splits the window with given index to two windows. First of those will have size specified by
- * the argument, the other one will fill up the rest of the original window.
- *
- * @param index
- * @param size
- */
- private void splitWindow(int index, int size)
- {
- PageWindowInternal window = windows.get(index);
- int delta = window.filePartSize - size;
-
- if (index == windows.size() - 1)
- {
- // if this is last window
- totalSize -= delta;
- window.filePartSize = size;
- }
- else if (window.filePartSize != size)
- {
- PageWindowInternal newWindow = new PageWindowInternal();
- newWindow.pageId = -1;
- window.filePartSize = size;
-
- windows.add(index + 1, newWindow);
-
- newWindow.filePartOffset = getWindowFileOffset(index + 1);
- newWindow.filePartSize = delta;
- }
-
- idToWindowIndex = null;
- windowIndexToPageId = null;
- }
-
- /**
- * Merges the window with given index with the next window. The resulting window will have size
- * of the two windows summed together.
- *
- * @param index
- */
- private void mergeWindowWithNext(int index)
- {
- if (index < windows.size() - 1)
- {
- PageWindowInternal window = windows.get(index);
- PageWindowInternal next = windows.get(index + 1);
- window.filePartSize += next.filePartSize;
-
- windows.remove(index + 1);
- idToWindowIndex = null; // reset index
- windowIndexToPageId = null;
- }
- }
-
- /**
- * Adjusts the window on given index to the specified size. If the new size is smaller than the
- * window size, the window will be split. Otherwise the window will be merged with as many
- * subsequent window as necessary. In case the window is last window in the file, the size will
- * be adjusted without splitting or merging.
- *
- * @param index
- * @param size
- */
- private void adjustWindowSize(int index, int size)
- {
- PageWindowInternal window = windows.get(index);
-
- // last window, just adjust size
- if (index == windows.size() - 1)
- {
- int delta = size - window.filePartSize;
- totalSize += delta;
- window.filePartSize = size;
- }
- else
- {
- // merge as many times as necessary
- while (window.filePartSize < size && index < windows.size() - 1)
- {
- mergeWindowWithNext(index);
- }
-
- // done merging - do we have enough room ?
- if (window.filePartSize < size)
- {
- // no, this is the last window
- int delta = size - window.filePartSize;
- totalSize += delta;
- window.filePartSize = size;
- }
- else
- {
- // yes, we might want to split the window, so that we don't lose
- // space when the created window was too big
- splitWindow(index, size);
- }
- }
-
- window.pageId = -1;
- }
-
- /**
- * Allocates window on given index with to size. If the index is pointing to existing window,
- * the window size will be adjusted. Otherwise a new window with appropriated size will be
- * created.
- *
- * @param index
- * @param size
- * @return page window
- */
- private PageWindowInternal allocatePageWindow(int index, int size)
- {
- final PageWindowInternal window;
-
- // new window
- if (index == windows.size())
- {
- // new page window
- window = new PageWindowInternal();
- window.filePartOffset = getWindowFileOffset(index);
- totalSize += size;
- window.filePartSize = size;
- windows.add(window);
- }
- else
- {
- // get the window
- window = windows.get(index);
-
- // adjust if necessary
- if (window.filePartSize != size)
- {
- adjustWindowSize(index, size);
- }
- }
-
- return window;
- }
-
- /**
- * Public (read only) version of page window.
- *
- * @author Matej Knopp
- */
- public static class PageWindow
- {
- private final PageWindowInternal pageWindowInternal;
-
- /**
- * Construct.
- *
- * @param pageWindowInternal
- */
- private PageWindow(PageWindowInternal pageWindowInternal)
- {
- this.pageWindowInternal = pageWindowInternal;
- }
-
- /**
- * @return page Id
- */
- public int getPageId()
- {
- return pageWindowInternal.pageId;
- }
-
- /**
- * @return offset in the pagemap file where the serialized page data starts
- */
- public int getFilePartOffset()
- {
- return pageWindowInternal.filePartOffset;
- }
-
- /**
- * @return size of the serialized page data
- */
- public int getFilePartSize()
- {
- return pageWindowInternal.filePartSize;
- }
- }
-
- /**
- * Creates and returns a new page window for given page.
- *
- * @param pageId
- * @param size
- * @return page window
- */
- public synchronized PageWindow createPageWindow(int pageId, int size)
- {
- int index = getWindowIndex(pageId);
-
- // if we found the page window, mark it as invalid
- if (index != -1)
- {
- removeWindowIndex(pageId);
- (windows.get(index)).pageId = -1;
- }
-
- // if we are not going to reuse a page window (because it's not on
- // indexPointer position or because we didn't find it), increment the
- // indexPointer
- if (index == -1 || index != indexPointer)
- {
- index = incrementIndexPointer();
- }
-
- PageWindowInternal window = allocatePageWindow(index, size);
- window.pageId = pageId;
-
- putWindowIndex(pageId, index);
- return new PageWindow(window);
- }
-
- /**
- * Returns the page window for given page or null if no window was found.
- *
- * @param pageId
- * @return page window or null
- */
- public synchronized PageWindow getPageWindow(int pageId)
- {
- int index = getWindowIndex(pageId);
- if (index != -1)
- {
- return new PageWindow(windows.get(index));
- }
- return null;
- }
-
- /**
- * Removes the page window for given page.
- *
- * @param pageId
- */
- public synchronized void removePage(int pageId)
- {
- int index = getWindowIndex(pageId);
- if (index != -1)
- {
- PageWindowInternal window = windows.get(index);
- removeWindowIndex(pageId);
- if (index == windows.size() - 1)
- {
- windows.remove(index);
- totalSize -= window.filePartSize;
- if (indexPointer == index)
- {
- --indexPointer;
- }
- }
- else
- {
- window.pageId = -1;
- }
- }
- }
-
- /**
- * Returns last n saved page windows.
- *
- * @param count
- * @return list of page windows
- */
- public synchronized List<PageWindow> getLastPageWindows(int count)
- {
- List<PageWindow> result = new ArrayList<PageWindow>();
-
- // start from current index to 0
- int currentIndex = indexPointer;
-
- do
- {
- if (currentIndex == -1)
- {
- break;
- }
-
- if (currentIndex < windows.size())
- {
- PageWindowInternal window = windows.get(currentIndex);
- if (window.pageId != -1)
- {
- result.add(new PageWindow(window));
- }
- }
-
- --currentIndex;
- if (currentIndex == -1)
- {
- // rewind to the last entry and collect all entries until current index
- currentIndex = windows.size() - 1;
- }
- }
- while (result.size() < count && currentIndex != indexPointer);
-
- return result;
- }
-
- /**
- * Creates a new PageWindowManager.
- *
- * @param maxSize
- * maximum page size. After this size is exceeded, the pages will be saved starting
- * at the beginning of file
- */
- public PageWindowManager(long maxSize)
- {
- this.maxSize = maxSize;
- }
-
- /**
- * Returns the size of all saved pages
- *
- * @return total size
- */
- public synchronized int getTotalSize()
- {
- return totalSize;
- }
-}
http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/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
deleted file mode 100644
index 4a21f4c..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/pageStore/PerSessionPageStore.java
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * 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.Iterator;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-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;
-
-/**
- * A page store that uses a SecondLevelPageCache with the last N used page instances
- * per session.
- *
- * <strong>Note</strong>: the size of the cache depends on the {@code cacheSize} constructor
- * parameter multiplied by the number of the active http sessions.
- *
- * It depends on the application use cases but usually a reasonable value of
- * {@code cacheSize} would be just a few pages (2-3). If the application don't expect many
- * active http sessions and the work flow involves usage of the browser/application history
- * then the {@code cacheSize} value may be increased to a bigger value.
- */
-public class PerSessionPageStore extends AbstractCachingPageStore<IManageablePage>
-{
- /**
- * Constructor.
- *
- * @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, new PagesCache(cacheSize));
- }
-
- @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);
- }
-
- /**
- * An implementation of SecondLevelPageCache that stores the last used N live page instances
- * per http session.
- */
- 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 long accessTime;
-
- private PageValue(IManageablePage page)
- {
- this(page.getPageId());
- }
-
- private PageValue(int pageId)
- {
- this.pageId = pageId;
- touch();
- }
-
- /**
- * Updates the access time with the current time
- */
- private void touch()
- {
- accessTime = System.nanoTime();
- }
-
- @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 Long.compare(p1.accessTime, p2.accessTime);
- }
- }
-
- private final int maxEntriesPerSession;
-
- private final ConcurrentMap<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 ConcurrentHashMap<>();
- }
-
- /**
- *
- * @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 sample = new PageValue(pageId);
- Iterator<Map.Entry<PageValue, IManageablePage>> iterator = pages.entrySet().iterator();
- while (iterator.hasNext())
- {
- Map.Entry<PageValue, IManageablePage> entry = iterator.next();
- if (sample.equals(entry.getKey()))
- {
- result = entry.getValue();
- iterator.remove();
- break;
- }
- }
- }
- }
- }
-
- 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 sample = new PageValue(pageId);
- for (Map.Entry<PageValue, IManageablePage> entry : pages.entrySet())
- {
- if (sample.equals(entry.getKey()))
- {
- // touch the entry
- entry.getKey().touch();
- result = entry.getValue();
- break;
- }
- }
- }
- }
- }
- 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)
- {
- removePage(sessionId, pageId);
-
- PageValue pv = new PageValue(page);
- pages.put(pv, page);
-
- while (pages.size() > maxEntriesPerSession)
- {
- pages.pollFirstEntry();
- }
- }
- }
- }
-
- @Override
- public void destroy()
- {
- cache.clear();
- }
- }
-
- @Override
- public boolean canBeAsynchronous()
- {
- return false; // NOTE: not analyzed neither tested yet, this page store being wrapped by asynchronous one
- }
-}
http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/RequestPageStore.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/RequestPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/RequestPageStore.java
new file mode 100644
index 0000000..2420768
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/RequestPageStore.java
@@ -0,0 +1,159 @@
+/*
+ * 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.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.wicket.MetaDataKey;
+import org.apache.wicket.page.IManageablePage;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Buffer pages till the end of the request, when they are delegated to another store in
+ * the reverse order they where accessed.
+ */
+public class RequestPageStore extends DelegatingPageStore
+{
+
+ private static final Logger log = LoggerFactory.getLogger(RequestPageStore.class);
+
+ private static final MetaDataKey<RequestData> KEY = new MetaDataKey<>()
+ {
+ private static final long serialVersionUID = 1L;
+ };
+
+ public RequestPageStore(IPageStore delegate)
+ {
+ super(delegate);
+ }
+
+ @Override
+ public IManageablePage getPage(IPageContext context, int id)
+ {
+ IManageablePage page = getRequestData(context).get(id);
+ if (page != null)
+ {
+ return page;
+ }
+
+ return super.getPage(context, id);
+ }
+
+ @Override
+ public void addPage(IPageContext context, IManageablePage page)
+ {
+ getRequestData(context).add(page);
+ }
+
+ @Override
+ public void removePage(IPageContext context, IManageablePage page)
+ {
+ getRequestData(context).remove(page);
+
+ super.removePage(context, page);
+ }
+
+ @Override
+ public void removeAllPages(IPageContext context)
+ {
+ getRequestData(context).removeAll();
+
+ super.removeAllPages(context);
+ }
+
+ @Override
+ public void detach(IPageContext context)
+ {
+ RequestData requestData = getRequestData(context);
+ for (IManageablePage page : requestData.pages())
+ {
+ boolean isPageStateless;
+ try
+ {
+ isPageStateless = page.isPageStateless();
+ }
+ catch (Exception x)
+ {
+ log.warn("An error occurred while checking whether a page is stateless. Assuming it is stateful.", x);
+ isPageStateless = false;
+ }
+
+ if (isPageStateless == false)
+ {
+ super.addPage(context, page);
+ }
+ }
+ requestData.removeAll();
+
+ super.detach(context);
+ }
+
+ private RequestData getRequestData(IPageContext context)
+ {
+ RequestData requestData = context.getRequestData(KEY);
+ if (requestData == null)
+ {
+ requestData = new RequestData();
+
+ context.setRequestData(KEY, requestData);
+ }
+ return requestData;
+ }
+
+ /**
+ * Data kept in the {@link RequestCycle}.
+ */
+ static class RequestData
+ {
+ private Map<Integer, IManageablePage> pages = new LinkedHashMap<>();
+
+ public void add(IManageablePage page)
+ {
+ pages.remove(page.getPageId());
+
+ pages.put(page.getPageId(), page);
+ }
+
+ public Iterable<IManageablePage> pages()
+ {
+ return pages.values();
+ }
+
+ public IManageablePage get(int id) {
+ IManageablePage page = pages.get(id);
+
+ if (page != null) {
+ pages.put(id, page);
+ }
+
+ return page;
+ }
+
+ public void remove(IManageablePage page)
+ {
+ pages.remove(page.getPageId());
+ }
+
+ public void removeAll()
+ {
+ pages.clear();
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/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
deleted file mode 100644
index 3d30857..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/pageStore/SecondLevelPageCache.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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);
-
- void destroy();
-}
http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/disk/PageWindowManager.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/disk/PageWindowManager.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/disk/PageWindowManager.java
new file mode 100644
index 0000000..5f59d34
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/disk/PageWindowManager.java
@@ -0,0 +1,493 @@
+/*
+ * 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.disk;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.wicket.pageStore.IPersistedPage;
+import org.apache.wicket.util.collections.IntHashMap;
+import org.apache.wicket.util.lang.Bytes;
+
+/**
+ * Manages positions and size of chunks of data in a file.
+ * <p>
+ * The data is stored inside the file in a cyclic way. Newer pages are placed after older ones,
+ * until the maximum file size is reached. After that, the next page is stored in the beginning of
+ * the file.
+ *
+ * @author Matej Knopp
+ */
+public class PageWindowManager implements Serializable
+{
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Contains information about a page inside the file.
+ *
+ * @author Matej Knopp
+ */
+ public static class FileWindow implements IPersistedPage, Serializable
+ {
+ private static final long serialVersionUID = 1L;
+
+ /** id of data or -1 if the window is empty */
+ private int id;
+
+ private String type;
+
+ /** offset in the file where the serialized page data begins */
+ private int filePartOffset;
+
+ /** size of serialized page data */
+ private int filePartSize;
+
+ @Override
+ public int getPageId()
+ {
+ return id;
+ }
+
+ @Override
+ public String getPageType() {
+ return type;
+ }
+
+ @Override
+ public Bytes getPageSize()
+ {
+ return Bytes.bytes(filePartSize);
+ }
+
+ public int getFilePartOffset()
+ {
+ return filePartOffset;
+ }
+
+ public int getFilePartSize()
+ {
+ return filePartSize;
+ }
+ }
+
+ private final List<FileWindow> windows = new ArrayList<FileWindow>();
+
+ /**
+ * map from page id to list of pagewindow indices (referring to the windows list) - to improve
+ * searching speed the index must be cleaned when the instances in the windows list change their
+ * indexes (e.g. items are shifted on page window removal)
+ */
+ private IntHashMap<Integer> idToWindowIndex = null;
+
+ /**
+ * Inversed index of #idToWindowIndex
+ */
+ private IntHashMap<Integer> windowIndexToPageId = null;
+
+ /** index of last added page */
+ private int indexPointer = -1;
+
+ private int totalSize = 0;
+
+ /**
+ * Maximum page size. After this size is exceeded, the pages will be saved starting at the
+ * beginning of file.
+ */
+ private final long maxSize;
+
+ /**
+ *
+ * @param pageId
+ * @param windowIndex
+ */
+ private void putWindowIndex(int pageId, int windowIndex)
+ {
+ if (idToWindowIndex != null && pageId != -1 && windowIndex != -1)
+ {
+ Integer oldPageId = windowIndexToPageId.remove(windowIndex);
+ if (oldPageId != null)
+ {
+ idToWindowIndex.remove(oldPageId);
+ }
+ idToWindowIndex.put(pageId, windowIndex);
+ windowIndexToPageId.put(windowIndex, pageId);
+ }
+ }
+
+ /**
+ *
+ * @param pageId
+ */
+ private void removeWindowIndex(int pageId)
+ {
+ Integer windowIndex = idToWindowIndex.remove(pageId);
+ if (windowIndex != null)
+ {
+ windowIndexToPageId.remove(windowIndex);
+ }
+ }
+
+ /**
+ *
+ */
+ private void rebuildIndices()
+ {
+ idToWindowIndex = null;
+ idToWindowIndex = new IntHashMap<Integer>();
+ windowIndexToPageId = null;
+ windowIndexToPageId = new IntHashMap<Integer>();
+ for (int i = 0; i < windows.size(); ++i)
+ {
+ FileWindow window = windows.get(i);
+ putWindowIndex(window.id, i);
+ }
+ }
+
+ /**
+ * Returns the index of the given page in the {@link #windows} list.
+ *
+ * @param pageId
+ * @return window index
+ */
+ private int getWindowIndex(int pageId)
+ {
+ if (idToWindowIndex == null)
+ {
+ rebuildIndices();
+ }
+
+ Integer result = idToWindowIndex.get(pageId);
+ return result != null ? result : -1;
+ }
+
+ /**
+ * Increments the {@link #indexPointer}. If the maximum file size has been reached, the
+ * {@link #indexPointer} is set to 0.
+ *
+ * @return new index pointer
+ */
+ private int incrementIndexPointer()
+ {
+ if ((maxSize > 0) && (totalSize >= maxSize) && (indexPointer == windows.size() - 1))
+ {
+ indexPointer = 0;
+ }
+ else
+ {
+ ++indexPointer;
+ }
+ return indexPointer;
+ }
+
+ /**
+ * Returns the offset in file of the window on given index. The offset is counted by getting the
+ * previous page offset and adding the previous page size to it.
+ *
+ * @param index
+ * @return window file offset
+ */
+ private int getWindowFileOffset(int index)
+ {
+ if (index > 0)
+ {
+ FileWindow window = windows.get(index - 1);
+ return window.filePartOffset + window.filePartSize;
+ }
+ return 0;
+ }
+
+ /**
+ * Splits the window with given index to two windows. First of those will have size specified by
+ * the argument, the other one will fill up the rest of the original window.
+ *
+ * @param index
+ * @param size
+ */
+ private void splitWindow(int index, int size)
+ {
+ FileWindow window = windows.get(index);
+ int delta = window.filePartSize - size;
+
+ if (index == windows.size() - 1)
+ {
+ // if this is last window
+ totalSize -= delta;
+ window.filePartSize = size;
+ }
+ else if (window.filePartSize != size)
+ {
+ FileWindow newWindow = new FileWindow();
+ newWindow.id = -1;
+ window.filePartSize = size;
+
+ windows.add(index + 1, newWindow);
+
+ newWindow.filePartOffset = getWindowFileOffset(index + 1);
+ newWindow.filePartSize = delta;
+ }
+
+ idToWindowIndex = null;
+ windowIndexToPageId = null;
+ }
+
+ /**
+ * Merges the window with given index with the next window. The resulting window will have size
+ * of the two windows summed together.
+ *
+ * @param index
+ */
+ private void mergeWindowWithNext(int index)
+ {
+ if (index < windows.size() - 1)
+ {
+ FileWindow window = windows.get(index);
+ FileWindow next = windows.get(index + 1);
+ window.filePartSize += next.filePartSize;
+
+ windows.remove(index + 1);
+ idToWindowIndex = null; // reset index
+ windowIndexToPageId = null;
+ }
+ }
+
+ /**
+ * Adjusts the window on given index to the specified size. If the new size is smaller than the
+ * window size, the window will be split. Otherwise the window will be merged with as many
+ * subsequent window as necessary. In case the window is last window in the file, the size will
+ * be adjusted without splitting or merging.
+ *
+ * @param index
+ * @param size
+ */
+ private void adjustWindowSize(int index, int size)
+ {
+ FileWindow window = windows.get(index);
+
+ // last window, just adjust size
+ if (index == windows.size() - 1)
+ {
+ int delta = size - window.filePartSize;
+ totalSize += delta;
+ window.filePartSize = size;
+ }
+ else
+ {
+ // merge as many times as necessary
+ while (window.filePartSize < size && index < windows.size() - 1)
+ {
+ mergeWindowWithNext(index);
+ }
+
+ // done merging - do we have enough room ?
+ if (window.filePartSize < size)
+ {
+ // no, this is the last window
+ int delta = size - window.filePartSize;
+ totalSize += delta;
+ window.filePartSize = size;
+ }
+ else
+ {
+ // yes, we might want to split the window, so that we don't lose
+ // space when the created window was too big
+ splitWindow(index, size);
+ }
+ }
+
+ window.id = -1;
+ }
+
+ /**
+ * Allocates window on given index with to size. If the index is pointing to existing window,
+ * the window size will be adjusted. Otherwise a new window with appropriated size will be
+ * created.
+ *
+ * @param index
+ * @param size
+ * @return page window
+ */
+ private FileWindow allocatePageWindow(int index, int size)
+ {
+ final FileWindow window;
+
+ // new window
+ if (index == windows.size())
+ {
+ // new page window
+ window = new FileWindow();
+ window.filePartOffset = getWindowFileOffset(index);
+ totalSize += size;
+ window.filePartSize = size;
+ windows.add(window);
+ }
+ else
+ {
+ // get the window
+ window = windows.get(index);
+
+ // adjust if necessary
+ if (window.filePartSize != size)
+ {
+ adjustWindowSize(index, size);
+ }
+ }
+
+ return window;
+ }
+
+ /**
+ * Creates and returns a new page window for given page.
+ *
+ * @param pageId
+ * @param type
+ * @param size
+ * @return page window
+ */
+ public synchronized FileWindow createPageWindow(int pageId, Class<?> type, int size)
+ {
+ int index = getWindowIndex(pageId);
+
+ // if we found the page window, mark it as invalid
+ if (index != -1)
+ {
+ removeWindowIndex(pageId);
+ (windows.get(index)).id = -1;
+ }
+
+ // if we are not going to reuse a page window (because it's not on
+ // indexPointer position or because we didn't find it), increment the
+ // indexPointer
+ if (index == -1 || index != indexPointer)
+ {
+ index = incrementIndexPointer();
+ }
+
+ FileWindow window = allocatePageWindow(index, size);
+ window.id = pageId;
+ window.type = type.getName();
+
+ putWindowIndex(pageId, index);
+ return window;
+ }
+
+ /**
+ * Returns the page window for given page or null if no window was found.
+ *
+ * @param pageId
+ * @return page window or null
+ */
+ public synchronized FileWindow getPageWindow(int pageId)
+ {
+ int index = getWindowIndex(pageId);
+ if (index != -1)
+ {
+ return windows.get(index);
+ }
+ return null;
+ }
+
+ /**
+ * Removes the page window for given page.
+ *
+ * @param pageId
+ */
+ public synchronized void removePage(int pageId)
+ {
+ int index = getWindowIndex(pageId);
+ if (index != -1)
+ {
+ FileWindow window = windows.get(index);
+ removeWindowIndex(pageId);
+ if (index == windows.size() - 1)
+ {
+ windows.remove(index);
+ totalSize -= window.filePartSize;
+ if (indexPointer == index)
+ {
+ --indexPointer;
+ }
+ }
+ else
+ {
+ window.id = -1;
+ }
+ }
+ }
+
+ /**
+ * Returns last n saved page windows.
+ *
+ * @return list of page windows
+ */
+ public synchronized List<FileWindow> getFileWindows()
+ {
+ List<FileWindow> result = new ArrayList<FileWindow>();
+
+ // start from current index to 0
+ int currentIndex = indexPointer;
+
+ do
+ {
+ if (currentIndex == -1)
+ {
+ break;
+ }
+
+ if (currentIndex < windows.size())
+ {
+ FileWindow window = windows.get(currentIndex);
+ if (window.id != -1)
+ {
+ result.add(window);
+ }
+ }
+
+ --currentIndex;
+ if (currentIndex == -1)
+ {
+ // rewind to the last entry and collect all entries until current index
+ currentIndex = windows.size() - 1;
+ }
+ }
+ while (currentIndex != indexPointer);
+
+ return result;
+ }
+
+ /**
+ * Creates a new PageWindowManager.
+ *
+ * @param maxSize
+ * maximum page size. After this size is exceeded, the pages will be saved starting
+ * at the beginning of file
+ */
+ public PageWindowManager(long maxSize)
+ {
+ this.maxSize = maxSize;
+ }
+
+ /**
+ * Returns the size of all saved pages
+ *
+ * @return total size
+ */
+ public synchronized int getTotalSize()
+ {
+ return totalSize;
+ }
+}
http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/HttpSessionDataStore.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/HttpSessionDataStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/HttpSessionDataStore.java
deleted file mode 100644
index fcc4f7a..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/HttpSessionDataStore.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * 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.memory;
-
-import javax.servlet.http.HttpSession;
-
-import org.apache.wicket.Session;
-import org.apache.wicket.page.IPageManagerContext;
-import org.apache.wicket.pageStore.IDataStore;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A {@link IDataStore} which stores the pages in the {@link HttpSession}. Uses
- * {@link IDataStoreEvictionStrategy} to keep the memory footprint reasonable.
- *
- * <p>
- * Usage:
- *
- * <pre>
- * <!--@formatter:off-->
- * MyApp#init()
- * {
- *
- * setPageManagerProvider(new DefaultPageManagerProvider(this)
- * {
- * protected IDataStore newDataStore()
- * {
- * return new HttpSessionDataStore(pageManagerContext, new PageNumberEvictionStrategy(20));
- * }
- * }
- * }
- * <!--@formatter:on-->
- * </pre>
- */
-public class HttpSessionDataStore implements IDataStore
-{
- private static final Logger LOG = LoggerFactory.getLogger(HttpSessionDataStore.class);
-
- /** the session attribute key. auto-prefixed with application.getSessionAttributePrefix() */
- private static final String PAGE_TABLE_KEY = "page:store:memory";
-
- private final IPageManagerContext pageManagerContext;
-
- private final IDataStoreEvictionStrategy evictionStrategy;
-
- /**
- * Construct.
- *
- * @param pageManagerContext
- * @param evictionStrategy
- */
- public HttpSessionDataStore(IPageManagerContext pageManagerContext,
- IDataStoreEvictionStrategy evictionStrategy)
- {
- this.pageManagerContext = pageManagerContext;
- this.evictionStrategy = evictionStrategy;
- }
-
- /**
- * @param sessionId
- * Ignored. Only pages from the current http session can be read
- * @see org.apache.wicket.pageStore.IDataStore#getData(java.lang.String, int)
- */
- @Override
- public byte[] getData(String sessionId, int pageId)
- {
- PageTable pageTable = getPageTable(false, false);
- byte[] pageAsBytes = null;
- if (pageTable != null)
- {
- pageAsBytes = pageTable.getPage(pageId);
- }
-
- if (LOG.isDebugEnabled())
- {
- int bytesLength = pageAsBytes != null ? pageAsBytes.length : -1;
- LOG.debug("Loaded '{}' bytes for page with id '{}' in session '{}'",
- bytesLength, pageId, sessionId);
- }
-
-
- return pageAsBytes;
- }
-
- @Override
- public void removeData(String sessionId, int pageId)
- {
- PageTable pageTable = getPageTable(false, true);
- if (pageTable != null)
- {
- byte[] bytes = pageTable.removePage(pageId);
-
- if (LOG.isDebugEnabled() && bytes != null)
- {
- LOG.debug("Removed page '{}' in session '{}'", pageId, sessionId);
- }
- }
- }
-
- @Override
- public void removeData(String sessionId)
- {
- PageTable pageTable = getPageTable(false, true);
- if (pageTable != null)
- {
- pageTable.clear();
- LOG.debug("Removed all pages in session '{}'", sessionId);
- }
- }
-
- @Override
- public void storeData(String sessionId, int pageId, byte[] pageAsBytes)
- {
- PageTable pageTable = getPageTable(true, true);
- if (pageTable != null)
- {
- pageTable.storePage(pageId, pageAsBytes);
- if (LOG.isDebugEnabled())
- {
- LOG.debug("Stored '{}' bytes for page '{}' in session '{}'",
- pageAsBytes.length, pageId, sessionId);
- }
- evictionStrategy.evict(pageTable);
- }
- else
- {
- LOG.error("Cannot store the data for page with id '{}' in session with id '{}'",
- pageId, sessionId);
- }
- }
-
- @Override
- public void destroy()
- {
- // do nothing
- // this is application lifecycle thread (WicketFilter#destroy())
- // so there is no reachable http session
- }
-
- @Override
- public boolean isReplicated()
- {
- return true;
- }
-
- private PageTable getPageTable(boolean create, boolean rewriteToSession)
- {
- PageTable pageTable = null;
- if (Session.exists())
- {
- pageTable = (PageTable)pageManagerContext.getSessionAttribute(PAGE_TABLE_KEY);
- if (pageTable == null && create)
- {
- pageTable = new PageTable();
- pageManagerContext.setSessionAttribute(PAGE_TABLE_KEY, pageTable);
- } else if (rewriteToSession) {
- pageManagerContext.setSessionAttribute(PAGE_TABLE_KEY, pageTable);
- }
- }
- return pageTable;
- }
-
- @Override
- public final boolean canBeAsynchronous()
- {
- // HttpSessionDataStore needs access to the current http session
- // and this is not possible in AsychronousDataStore
- return false;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/IDataStoreEvictionStrategy.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/IDataStoreEvictionStrategy.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/IDataStoreEvictionStrategy.java
deleted file mode 100644
index 6b6e556..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/IDataStoreEvictionStrategy.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.memory;
-
-
-/**
- * An eviction strategy that decides whether the in-memory data structure used as page store should
- * be compacted
- */
-@FunctionalInterface
-public interface IDataStoreEvictionStrategy
-{
-
- /**
- * Called after each {@link org.apache.wicket.pageStore.IDataStore#storeData(String, int, byte[])} call.
- *
- * @param pageTable
- * the in-memory data store with <strong>all</strong> pages
- */
- void evict(PageTable pageTable);
-}
http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/MemorySizeEvictionStrategy.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/MemorySizeEvictionStrategy.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/MemorySizeEvictionStrategy.java
deleted file mode 100644
index 92f985b..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/MemorySizeEvictionStrategy.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.memory;
-
-import org.apache.wicket.util.lang.Args;
-import org.apache.wicket.util.lang.Bytes;
-import org.apache.wicket.core.util.lang.WicketObjects;
-
-/**
- * An eviction strategy that keeps the data store size up to configured bytes
- */
-public class MemorySizeEvictionStrategy implements IDataStoreEvictionStrategy
-{
-
- private final Bytes maxBytes;
-
- /**
- * Construct.
- *
- * @param maxBytes
- * the maximum size of the data store
- */
- public MemorySizeEvictionStrategy(Bytes maxBytes)
- {
- Args.notNull(maxBytes, "maxBytes");
-
- this.maxBytes = maxBytes;
- }
-
- /**
- *
- * @see IDataStoreEvictionStrategy#evict(org.apache.wicket.pageStore.memory.PageTable)
- */
- @Override
- public void evict(PageTable pageTable)
- {
-
- long storeCurrentSize = WicketObjects.sizeof(pageTable);
-
- if (storeCurrentSize > maxBytes.bytes())
- {
- PageTableCleaner cleaner = new PageTableCleaner();
- cleaner.drop(pageTable, 1);
-
- // recurse until enough space is cleaned
- evict(pageTable);
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageNumberEvictionStrategy.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageNumberEvictionStrategy.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageNumberEvictionStrategy.java
deleted file mode 100644
index 9857a6b..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageNumberEvictionStrategy.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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.memory;
-
-
-/**
- * An eviction strategy which decides whether to evict entries from the in-memory data store
- * depending on the number of stored paged per session
- */
-public class PageNumberEvictionStrategy implements IDataStoreEvictionStrategy
-{
-
- private final int pagesNumber;
-
- /**
- * Construct.
- *
- * @param pagesNumber
- * the maximum number of pages the data store can hold
- */
- public PageNumberEvictionStrategy(int pagesNumber)
- {
- if (pagesNumber < 1)
- {
- throw new IllegalArgumentException("'pagesNumber' must be greater than 0.");
- }
-
- this.pagesNumber = pagesNumber;
- }
-
- /**
- *
- * @see IDataStoreEvictionStrategy#evict(org.apache.wicket.pageStore.memory.PageTable)
- */
- @Override
- public void evict(PageTable pageTable)
- {
- int size = pageTable.size();
- int pagesToDrop = size - pagesNumber;
-
- if (pagesToDrop > 0)
- {
- PageTableCleaner cleaner = new PageTableCleaner();
- cleaner.drop(pageTable, pagesToDrop);
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageTable.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageTable.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageTable.java
deleted file mode 100644
index dfad4af..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageTable.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * 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.memory;
-
-import java.util.Iterator;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.ConcurrentMap;
-
-import org.apache.wicket.util.io.IClusterable;
-
-/**
- * A structure that holds page id => pageAsBytes.
- *
- * <p>
- * Additionally it has an index of the least recently used pages
- */
-public class PageTable implements IClusterable
-{
- private static final long serialVersionUID = 1L;
-
- /**
- * Holds the index of last/least recently used page ids. The most recently used page id is in
- * the tail, the least recently used is in the head.
- */
- /*
- * Can be replaced later with PriorityQueue to deal with lightweight (Ajax) and heavyweight
- * pages
- */
- private final Queue<Integer> index;
-
- /**
- * The actual container for the pages.
- *
- * <p>
- * page id => page as bytes
- */
- private final ConcurrentMap<Integer, byte[]> pages;
-
- public PageTable()
- {
- pages = new ConcurrentHashMap<>();
- index = new ConcurrentLinkedQueue<>();
- }
-
- public void storePage(Integer pageId, byte[] pageAsBytes)
- {
- synchronized (index)
- {
- pages.put(pageId, pageAsBytes);
-
- updateIndex(pageId);
- }
- }
-
- public byte[] getPage(final Integer pageId)
- {
- synchronized (index)
- {
- updateIndex(pageId);
-
- return pages.get(pageId);
- }
- }
-
- public byte[] removePage(Integer pageId)
- {
- synchronized (index)
- {
- index.remove(pageId);
-
- return pages.remove(pageId);
- }
- }
-
- public void clear()
- {
- synchronized (index)
- {
- index.clear();
- pages.clear();
- }
- }
-
- public int size()
- {
- return pages.size();
- }
-
- public Integer getOldest()
- {
- return index.peek();
- }
-
- public Iterator<Integer> indexIterator()
- {
- return index.iterator();
- }
-
- /**
- * Updates the index of last/least recently used pages by removing the page id from the index
- * (in case it is already in) and (re-)adding it at the head
- *
- * @param pageId
- * the id of a recently used page
- */
- private void updateIndex(Integer pageId)
- {
- index.remove(pageId);
- index.offer(pageId);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageTableCleaner.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageTableCleaner.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageTableCleaner.java
deleted file mode 100644
index 2c9a9cb..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageTableCleaner.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.memory;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Helper class that knows how to remove the nth oldest pages from {@link PageTable}
- */
-public class PageTableCleaner
-{
- private static final Logger LOG = LoggerFactory.getLogger(PageTableCleaner.class);
-
- /**
- * Removes {@code pagesNumber} of pages from the {@link PageTable pageTable}
- *
- * @param pageTable
- * the {@link PageTable} to clean
- * @param pagesNumber
- * the number of pages to remove
- */
- public void drop(final PageTable pageTable, final int pagesNumber)
- {
- for (int i = 0; i < pagesNumber; i++)
- {
- Integer pageIdOfTheOldest = pageTable.getOldest();
- pageTable.removePage(pageIdOfTheOldest);
- LOG.debug("Evicted page with id '{}' from the HttpSessionDataStore");
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/settings/StoreSettings.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/settings/StoreSettings.java b/wicket-core/src/main/java/org/apache/wicket/settings/StoreSettings.java
index 8852208..63a5499 100644
--- a/wicket-core/src/main/java/org/apache/wicket/settings/StoreSettings.java
+++ b/wicket-core/src/main/java/org/apache/wicket/settings/StoreSettings.java
@@ -50,8 +50,6 @@ public class StoreSettings
private static final int DEFAULT_ASYNCHRONOUS_QUEUE_CAPACITY = 100;
- private int inmemoryCacheSize = DEFAULT_CACHE_SIZE;
-
private Bytes maxSizePerSession = DEFAULT_MAX_SIZE_PER_SESSION;
private File fileStoreFolder = null;
@@ -70,30 +68,6 @@ public class StoreSettings
}
/**
- * @return the number of page instances which will be stored in the application scoped cache for
- * faster retrieval
- */
- public int getInmemoryCacheSize()
- {
- return inmemoryCacheSize;
- }
-
- /**
- * Sets the maximum number of page instances which will be stored in the application scoped
- * second level cache for faster retrieval
- *
- * @param inmemoryCacheSize
- * the maximum number of page instances which will be held in the application scoped
- * cache
- * @return {@code this} object for chaining
- */
- public StoreSettings setInmemoryCacheSize(int inmemoryCacheSize)
- {
- this.inmemoryCacheSize = inmemoryCacheSize;
- return this;
- }
-
- /**
* @return maximum page size. After this size is exceeded,
* the {@link org.apache.wicket.pageStore.DiskDataStore} will start saving the
* pages at the beginning of file.
http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/util/tester/BaseWicketTester.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/util/tester/BaseWicketTester.java b/wicket-core/src/main/java/org/apache/wicket/util/tester/BaseWicketTester.java
index 54e7808..4012a5f 100644
--- a/wicket-core/src/main/java/org/apache/wicket/util/tester/BaseWicketTester.java
+++ b/wicket-core/src/main/java/org/apache/wicket/util/tester/BaseWicketTester.java
@@ -92,11 +92,11 @@ import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.parser.XmlPullParser;
import org.apache.wicket.markup.parser.XmlTag;
import org.apache.wicket.mock.MockApplication;
-import org.apache.wicket.mock.MockPageManager;
+import org.apache.wicket.mock.MockPageStore;
import org.apache.wicket.mock.MockRequestParameters;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.page.IPageManager;
-import org.apache.wicket.page.IPageManagerContext;
+import org.apache.wicket.page.PageManager;
import org.apache.wicket.protocol.http.AjaxEnclosureListener;
import org.apache.wicket.protocol.http.IMetaDataBufferingWebResponse;
import org.apache.wicket.protocol.http.WebApplication;
@@ -2926,9 +2926,9 @@ public class BaseWicketTester
private static class TestPageManagerProvider implements IPageManagerProvider
{
@Override
- public IPageManager apply(IPageManagerContext pageManagerContext)
+ public IPageManager get()
{
- return new MockPageManager();
+ return new PageManager(new MockPageStore());
}
}