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 2017/04/12 21:28:26 UTC

[01/10] wicket git commit: WICKET-6177 Blocking page serialization

Repository: wicket
Updated Branches:
  refs/heads/master c45af373c -> 312bddbc4


WICKET-6177 Blocking page serialization


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

Branch: refs/heads/master
Commit: 2ffd587dea4c5e1edec0853f35a9b5761e391917
Parents: e8aea22
Author: manuelbarzi <ma...@manuelbarzis-MacBook-Pro.local>
Authored: Sun Feb 12 02:23:40 2017 +0100
Committer: manuelbarzi <ma...@manuelbarzis-MacBook-Pro.local>
Committed: Sun Feb 12 02:23:40 2017 +0100

----------------------------------------------------------------------
 pom.xml                                         |  10 +
 wicket-core/pom.xml                             |  10 +
 .../apache/wicket/pageStore/AsyncPageStore.java | 373 ++++++++++++++
 .../wicket/pageStore/AsyncPageStoreTest.java    | 497 +++++++++++++++++++
 4 files changed, 890 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/2ffd587d/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index d5beb05..80e236d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -151,6 +151,11 @@
 				<scope>provided</scope>
 			</dependency>
 			<dependency>
+				<groupId>com.google.guava</groupId>
+				<artifactId>guava</artifactId>
+				<version>21.0</version>
+			</dependency>
+			<dependency>
 				<groupId>javax.el</groupId>
 				<artifactId>javax.el-api</artifactId>
 				<version>3.0.1-b04</version>
@@ -242,6 +247,11 @@
 				<version>4.1</version>
 			</dependency>
 			<dependency>
+				<groupId>org.apache.commons</groupId>
+				<artifactId>commons-lang3</artifactId>
+				<version>3.5</version>
+			</dependency>
+			<dependency>
 				<groupId>org.apache.velocity</groupId>
 				<artifactId>velocity</artifactId>
 				<version>1.7</version>

http://git-wip-us.apache.org/repos/asf/wicket/blob/2ffd587d/wicket-core/pom.xml
----------------------------------------------------------------------
diff --git a/wicket-core/pom.xml b/wicket-core/pom.xml
index bcc8d1d..a1ee73d 100644
--- a/wicket-core/pom.xml
+++ b/wicket-core/pom.xml
@@ -66,6 +66,16 @@
 		    <groupId>com.tdunning</groupId>
 		    <artifactId>json</artifactId>
 		</dependency>
+		<dependency>
+			<groupId>com.google.guava</groupId>
+			<artifactId>guava</artifactId>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-lang3</artifactId>
+			<scope>test</scope>
+		</dependency>
 	</dependencies>
 	<build>
 		<pluginManagement>

http://git-wip-us.apache.org/repos/asf/wicket/blob/2ffd587d/wicket-core/src/main/java/org/apache/wicket/pageStore/AsyncPageStore.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/AsyncPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/AsyncPageStore.java
new file mode 100644
index 0000000..213164d
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/AsyncPageStore.java
@@ -0,0 +1,373 @@
+package org.apache.wicket.pageStore;
+
+import java.io.Serializable;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.wicket.page.IManageablePage;
+import org.apache.wicket.util.lang.Args;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Facade for {@link IPageStore} that does the actual saving in worker thread.
+ * <p>
+ * Creates an {@link Entry} for each double (sessionId, page) and puts it in {@link #entries} queue
+ * if there is room. Acts as producer.<br/>
+ * Later {@link PageSavingRunnable} reads in blocking manner from {@link #entries} and saves each
+ * entry. Acts as consumer.
+ * </p>
+ * It starts only one instance of {@link PageSavingRunnable} because all we need is to make the page
+ * storing asynchronous. We don't want to write concurrently in the wrapped {@link IPageStore},
+ * though it may happen in the extreme case when the queue is full. These cases should be avoided.
+ * 
+ * Based on AsynchronousDataStore (@author Matej Knopp).
+ * 
+ * @author manuelbarzi
+ */
+public class AsyncPageStore implements IPageStore
+{
+
+	/** Log for reporting. */
+	private static final Logger log = LoggerFactory.getLogger(AsyncPageStore.class);
+
+	/**
+	 * The time to wait when adding an {@link Entry} into the entries. In millis.
+	 */
+	private static final long OFFER_WAIT = 30L;
+
+	/**
+	 * The time to wait for an entry to save with the wrapped {@link IPageStore} . In millis.
+	 */
+	private static final long POLL_WAIT = 1000L;
+
+	/**
+	 * The page saving thread.
+	 */
+	private final Thread pageSavingThread;
+
+	/**
+	 * The wrapped {@link IPageStore} that actually stores that pages
+	 */
+	private final IPageStore pageStore;
+
+	/**
+	 * The queue where the entries which have to be saved are temporary stored
+	 */
+	private final BlockingQueue<Entry> entries;
+
+	/**
+	 * A map 'sessionId:::pageId' -> {@link Entry}. Used for fast retrieval of {@link Entry}s which
+	 * are not yet stored by the wrapped {@link IPageStore}
+	 */
+	private final ConcurrentMap<String, Entry> entryMap;
+
+	/**
+	 * Construct.
+	 * 
+	 * @param pageStore
+	 *            the wrapped {@link IPageStore} that actually saved the page
+	 * @param capacity
+	 *            the capacity of the queue that delays the saving
+	 */
+	public AsyncPageStore(final IPageStore pageStore, final int capacity)
+	{
+		this.pageStore = pageStore;
+		entries = new LinkedBlockingQueue<Entry>(capacity);
+		entryMap = new ConcurrentHashMap<String, Entry>();
+
+		PageSavingRunnable savingRunnable = new PageSavingRunnable(pageStore, entries, entryMap);
+		pageSavingThread = new Thread(savingRunnable, "AsyncPageStore-PageSavingThread");
+		pageSavingThread.setDaemon(true);
+		pageSavingThread.start();
+	}
+
+	/**
+	 * Little helper
+	 * 
+	 * @param sessionId
+	 * @param pageId
+	 * @return Entry
+	 */
+	private Entry getEntry(final String sessionId, final int pageId)
+	{
+		return entryMap.get(getKey(sessionId, pageId));
+	}
+
+	/**
+	 * 
+	 * @param pageId
+	 * @param sessionId
+	 * @return generated key
+	 */
+	private static String getKey(final String sessionId, final int pageId)
+	{
+		return pageId + ":::" + sessionId;
+	}
+
+	/**
+	 * 
+	 * @param entry
+	 * @return generated key
+	 */
+	private static String getKey(final Entry entry)
+	{
+		return getKey(entry.sessionId, entry.page.getPageId());
+	}
+
+	/**
+	 * The structure used for an entry in the queue
+	 */
+	private static class Entry
+	{
+		private final String sessionId;
+		private final IManageablePage page;
+
+		public Entry(final String sessionId, final IManageablePage page)
+		{
+			this.sessionId = Args.notNull(sessionId, "sessionId");
+			this.page = Args.notNull(page, "page");
+		}
+
+		@Override
+		public int hashCode()
+		{
+			final int prime = 31;
+			int result = 1;
+			result = prime * result + page.getPageId();
+			result = prime * result + ((sessionId == null) ? 0 : sessionId.hashCode());
+			return result;
+		}
+
+		@Override
+		public boolean equals(Object obj)
+		{
+			if (this == obj)
+				return true;
+			if (obj == null)
+				return false;
+			if (getClass() != obj.getClass())
+				return false;
+			Entry other = (Entry)obj;
+			if (page.getPageId() != other.page.getPageId())
+				return false;
+			if (sessionId == null)
+			{
+				if (other.sessionId != null)
+					return false;
+			}
+			else if (!sessionId.equals(other.sessionId))
+				return false;
+			return true;
+		}
+
+		@Override
+		public String toString()
+		{
+			return "Entry [sessionId=" + sessionId + ", pageId=" + page.getPageId() + "]";
+		}
+
+	}
+
+	/**
+	 * The thread that acts as consumer of {@link Entry}ies
+	 */
+	private static class PageSavingRunnable implements Runnable
+	{
+		private static final Logger log = LoggerFactory.getLogger(PageSavingRunnable.class);
+
+		private final BlockingQueue<Entry> entries;
+
+		private final ConcurrentMap<String, Entry> entryMap;
+
+		private final IPageStore pageStore;
+
+		private PageSavingRunnable(IPageStore pageStore, BlockingQueue<Entry> entries,
+			ConcurrentMap<String, Entry> entryMap)
+		{
+			this.pageStore = pageStore;
+			this.entries = entries;
+			this.entryMap = entryMap;
+		}
+
+		@Override
+		public void run()
+		{
+			while (!Thread.interrupted())
+			{
+				Entry entry = null;
+				try
+				{
+					entry = entries.poll(POLL_WAIT, TimeUnit.MILLISECONDS);
+				}
+				catch (InterruptedException e)
+				{
+					Thread.currentThread().interrupt();
+				}
+
+				if (entry != null)
+				{
+					log.debug("Saving asynchronously: {}...", entry);
+					pageStore.storePage(entry.sessionId, entry.page);
+					entryMap.remove(getKey(entry));
+				}
+			}
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.wicket.pageStore.IPageStore#destroy()
+	 */
+	@Override
+	public void destroy()
+	{
+		if (pageSavingThread.isAlive())
+		{
+			pageSavingThread.interrupt();
+			try
+			{
+				pageSavingThread.join();
+			}
+			catch (InterruptedException e)
+			{
+				log.error(e.getMessage(), e);
+			}
+		}
+
+		pageStore.destroy();
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.wicket.pageStore.IPageStore#getPage(java.lang.String, int)
+	 */
+	@Override
+	public IManageablePage getPage(String sessionId, int pageId)
+	{
+		Entry entry = getEntry(sessionId, pageId);
+		if (entry != null)
+		{
+			log.debug(
+				"Returning the page of a non-stored entry with session id '{}' and page id '{}'",
+				sessionId, pageId);
+			return entry.page;
+		}
+		IManageablePage page = pageStore.getPage(sessionId, pageId);
+
+		log.debug("Returning the page of a stored entry with session id '{}' and page id '{}'",
+			sessionId, pageId);
+
+		return page;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.wicket.pageStore.IPageStore#removePage(java.lang.String, int)
+	 */
+	@Override
+	public void removePage(String sessionId, int pageId)
+	{
+		String key = getKey(sessionId, pageId);
+		if (key != null)
+		{
+			Entry entry = entryMap.remove(key);
+			if (entry != null)
+			{
+				entries.remove(entry);
+			}
+		}
+
+		pageStore.removePage(sessionId, pageId);
+
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.wicket.pageStore.IPageStore#storePage(java.lang.String,
+	 * org.apache.wicket.page.IManageablePage)
+	 */
+	@Override
+	public void storePage(String sessionId, IManageablePage page)
+	{
+		Entry entry = new Entry(sessionId, page);
+		String key = getKey(entry);
+		entryMap.put(key, entry);
+
+		try
+		{
+			if (entries.offer(entry, OFFER_WAIT, TimeUnit.MILLISECONDS))
+			{
+				log.debug("Offered for storing asynchronously page with id '{}' in session '{}'",
+					page.getPageId(), sessionId);
+			}
+			else
+			{
+				log.debug("Storing synchronously page with id '{}' in session '{}'",
+					page.getPageId(), sessionId);
+				entryMap.remove(key);
+				pageStore.storePage(sessionId, page);
+			}
+		}
+		catch (InterruptedException e)
+		{
+			log.error(e.getMessage(), e);
+			entryMap.remove(key);
+			pageStore.storePage(sessionId, page);
+		}
+
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.wicket.pageStore.IPageStore#unbind(java.lang.String)
+	 */
+	@Override
+	public void unbind(String sessionId)
+	{
+		pageStore.unbind(sessionId);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.wicket.pageStore.IPageStore#prepareForSerialization(java.lang. String,
+	 * java.io.Serializable)
+	 */
+	@Override
+	public Serializable prepareForSerialization(String sessionId, Serializable page)
+	{
+		return pageStore.prepareForSerialization(sessionId, page);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.wicket.pageStore.IPageStore#restoreAfterSerialization(java.io. Serializable)
+	 */
+	@Override
+	public Object restoreAfterSerialization(Serializable serializable)
+	{
+		return pageStore.restoreAfterSerialization(serializable);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.wicket.pageStore.IPageStore#convertToPage(java.lang.Object)
+	 */
+	@Override
+	public IManageablePage convertToPage(Object page)
+	{
+		return pageStore.convertToPage(page);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/2ffd587d/wicket-core/src/test/java/org/apache/wicket/pageStore/AsyncPageStoreTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/pageStore/AsyncPageStoreTest.java b/wicket-core/src/test/java/org/apache/wicket/pageStore/AsyncPageStoreTest.java
new file mode 100644
index 0000000..9849471
--- /dev/null
+++ b/wicket-core/src/test/java/org/apache/wicket/pageStore/AsyncPageStoreTest.java
@@ -0,0 +1,497 @@
+package org.apache.wicket.pageStore;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.lang3.RandomUtils;
+import org.apache.wicket.page.IManageablePage;
+import org.apache.wicket.serialize.ISerializer;
+import org.apache.wicket.serialize.java.DeflatedJavaSerializer;
+import org.apache.wicket.util.file.File;
+import org.apache.wicket.util.lang.Bytes;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Stopwatch;
+
+/**
+ * AsyncPageStoreTest
+ * 
+ * @author manuelbarzi
+ *
+ */
+public class AsyncPageStoreTest
+{
+
+	/** Log for reporting. */
+	private static final Logger log = LoggerFactory.getLogger(AsyncPageStoreTest.class);
+
+	@SuppressWarnings("serial")
+	private static class DummyPage implements IManageablePage
+	{
+
+		private int pageId;
+		private long writeMillis;
+		private long readMillis;
+		private String sessionId;
+
+		private DummyPage(int pageId, long writeMillis, long readMillis, String sessionId)
+		{
+			this.pageId = pageId;
+			this.writeMillis = writeMillis;
+			this.readMillis = readMillis;
+			this.sessionId = sessionId;
+		}
+
+		@Override
+		public boolean isPageStateless()
+		{
+			return false;
+		}
+
+		@Override
+		public int getPageId()
+		{
+			return pageId;
+		}
+
+		@Override
+		public void detach()
+		{
+		}
+
+		@Override
+		public boolean setFreezePageId(boolean freeze)
+		{
+			return false;
+		}
+
+		/**
+		 * @param s
+		 * @throws IOException
+		 */
+		private void writeObject(java.io.ObjectOutputStream s) throws IOException
+		{
+			log.debug("serializing page {} for {}ms (session {})", getPageId(), writeMillis,
+				sessionId);
+			try
+			{
+				Thread.sleep(writeMillis);
+			}
+			catch (InterruptedException e)
+			{
+				throw new RuntimeException(e);
+			}
+
+			s.writeInt(pageId);
+			s.writeLong(writeMillis);
+			s.writeLong(readMillis);
+			s.writeObject(sessionId);
+		}
+
+		private void readObject(java.io.ObjectInputStream s)
+			throws IOException, ClassNotFoundException
+		{
+			log.debug("deserializing page {} for {}ms (session {})", getPageId(), writeMillis,
+				sessionId);
+			try
+			{
+				Thread.sleep(readMillis);
+			}
+			catch (InterruptedException e)
+			{
+				throw new RuntimeException(e);
+			}
+
+			pageId = s.readInt();
+			writeMillis = s.readLong();
+			readMillis = s.readLong();
+			sessionId = (String)s.readObject();
+		}
+
+		public String toString()
+		{
+			return "DummyPage[pageId = " + pageId + ", writeMillis = " + writeMillis +
+				", readMillis = " + readMillis + ", sessionId = " + sessionId + ", hashCode = " +
+				hashCode() + "]";
+		}
+	}
+
+	/**
+	 * Store works fully async when number of pages handled never exceeds the async-storage
+	 * capacity.
+	 * 
+	 * @throws InterruptedException
+	 */
+	@Test
+	public void storeBehavesAsyncWhenNotExceedingStoreCapacity() throws InterruptedException
+	{
+		int sessions = 2;
+		int pages = 5;
+		long writeMillis = 2000;
+		long readMillis = 1500;
+		int asyncPageStoreCapacity = pages * sessions;
+
+		List<Metrics> results = runTest(sessions, pages, writeMillis, readMillis,
+			asyncPageStoreCapacity);
+
+		for (Metrics metrics : results)
+			System.out.println(metrics);
+
+		for (Metrics metrics : results)
+		{
+			assertEquals(metrics.storedPage, metrics.restoredPage);
+			assertTrue(metrics.storingMillis < writeMillis);
+			assertTrue(metrics.restoringMillis < readMillis);
+		}
+	}
+
+	/**
+	 * Store behaves sync from when number of pages handled exceeds the given async-storage
+	 * capacity. It works async until the number of pages reaches the limit (capacity).
+	 * 
+	 * @throws InterruptedException
+	 */
+	@Test
+	public void storeBehavesSyncFromWhenExceedingStoreCapacity() throws InterruptedException
+	{
+		int sessions = 2;
+		int pages = 5;
+		long writeMillis = 2000;
+		long readMillis = 1500;
+		int asyncPageStoreCapacity = pages; // only up to the first round of
+											// pages
+
+		List<Metrics> results = runTest(sessions, pages, writeMillis, readMillis,
+			asyncPageStoreCapacity);
+
+		for (Metrics metrics : results)
+			System.out.println(metrics);
+
+		int sync = 0;
+
+		for (int i = 0; i < results.size(); i++)
+		{
+			Metrics metrics = results.get(i);
+
+			assertEquals(metrics.storedPage.sessionId, metrics.restoredPage.sessionId);
+			assertEquals(metrics.storedPage.getPageId(), metrics.restoredPage.getPageId());
+
+			if (!metrics.storedPage.equals(metrics.restoredPage))
+			{
+				assertTrue(metrics.storingMillis >= metrics.storedPage.writeMillis);
+				sync++;
+			}
+		}
+
+		assertTrue(sync > 0);
+	}
+
+	// test run
+
+	private class Metrics
+	{
+		private DummyPage storedPage;
+		private long storingMillis;
+		private DummyPage restoredPage;
+		private long restoringMillis;
+
+		public String toString()
+		{
+			return "Metrics[storedPage = " + storedPage + ", storingMillis = " + storingMillis +
+				", restoredPage = " + restoredPage + ", restoringMillis = " + restoringMillis + "]";
+		}
+	}
+
+	private List<Metrics> runTest(int sessions, int pages, long writeMillis, long readMillis,
+		int asyncPageStoreCapacity) throws InterruptedException
+	{
+
+		List<Metrics> results = new ArrayList<>();
+
+		final CountDownLatch lock = new CountDownLatch(pages * sessions);
+
+		ISerializer serializer = new DeflatedJavaSerializer("applicationKey");
+		// ISerializer serializer = new DummySerializer();
+		IDataStore dataStore = new DiskDataStore("applicationName", new File("./target"),
+			Bytes.bytes(10000l));
+		IPageStore pageStore = new DefaultPageStore(serializer, dataStore, 0)
+		{
+			// IPageStore pageStore = new DummyPageStore(new
+			// File("target/store")) {
+
+			@Override
+			public void storePage(String sessionId, IManageablePage page)
+			{
+
+				super.storePage(sessionId, page);
+
+				lock.countDown();
+			}
+		};
+
+		IPageStore asyncPageStore = new AsyncPageStore(pageStore, asyncPageStoreCapacity);
+
+		Stopwatch stopwatch = Stopwatch.createUnstarted();
+
+		for (int pageId = 1; pageId <= pages; pageId++)
+		{
+			for (int sessionId = 1; sessionId <= sessions; sessionId++)
+			{
+				String session = String.valueOf(sessionId);
+				Metrics metrics = new Metrics();
+
+				stopwatch.reset();
+				DummyPage page = new DummyPage(pageId, around(writeMillis), around(readMillis),
+					session);
+				stopwatch.start();
+				asyncPageStore.storePage(session, page);
+				metrics.storedPage = page;
+				metrics.storingMillis = stopwatch.elapsed(TimeUnit.MILLISECONDS);
+
+				stopwatch.reset();
+				stopwatch.start();
+				metrics.restoredPage = DummyPage.class
+					.cast(asyncPageStore.getPage(session, pageId));
+				metrics.restoringMillis = stopwatch.elapsed(TimeUnit.MILLISECONDS);
+
+				results.add(metrics);
+			}
+		}
+
+		lock.await(pages * sessions * (writeMillis + readMillis), TimeUnit.MILLISECONDS);
+
+		return results;
+	}
+
+	private long around(long target)
+	{
+		return RandomUtils.nextLong((long)(target * .9), (long)(target * 1.1));
+	}
+
+	// other aux dummy impls for testing
+
+	private class DummySerializer implements ISerializer
+	{
+
+		@Override
+		public byte[] serialize(Object obj)
+		{
+			ByteArrayOutputStream bos = null;
+			ObjectOutput out = null;
+			try
+			{
+				bos = new ByteArrayOutputStream();
+				out = new ObjectOutputStream(bos);
+				out.writeObject(obj);
+				return bos.toByteArray();
+			}
+			catch (FileNotFoundException e)
+			{
+				throw new RuntimeException(e);
+			}
+			catch (IOException e)
+			{
+				throw new RuntimeException(e);
+			}
+			finally
+			{
+				try
+				{
+					if (bos != null)
+						bos.close();
+					if (out != null)
+						out.close();
+				}
+				catch (IOException e)
+				{
+					throw new RuntimeException(e);
+				}
+			}
+		}
+
+		@Override
+		public Object deserialize(byte[] bytes)
+		{
+			ByteArrayInputStream bis = null;
+			ObjectInput in = null;
+			try
+			{
+				bis = new ByteArrayInputStream(bytes);
+				in = new ObjectInputStream(bis);
+				return in.readObject();
+			}
+			catch (IOException e)
+			{
+				throw new RuntimeException(e);
+			}
+			catch (ClassNotFoundException e)
+			{
+				throw new RuntimeException(e);
+			}
+			finally
+			{
+				try
+				{
+					if (bis != null)
+						bis.close();
+					if (in != null)
+						in.close();
+				}
+				catch (IOException e)
+				{
+					throw new RuntimeException(e);
+				}
+			}
+		}
+
+	}
+
+	private class DummyPageStore implements IPageStore
+	{
+
+		private File folder;
+
+		private DummyPageStore(File folder)
+		{
+			folder.mkdirs();
+			this.folder = folder;
+		}
+
+		private File getPageFile(String sessionId, int pageId)
+		{
+			return new File(folder.getAbsolutePath() + "/" + sessionId + "-" + pageId + ".page");
+		}
+
+		private void toFile(Object obj, File file)
+		{
+			FileOutputStream fos = null;
+			ObjectOutput oo = null;
+			try
+			{
+				fos = new FileOutputStream(file);
+				oo = new ObjectOutputStream(fos);
+				oo.writeObject(obj);
+			}
+			catch (FileNotFoundException e)
+			{
+				throw new RuntimeException(e);
+			}
+			catch (IOException e)
+			{
+				throw new RuntimeException(e);
+			}
+			finally
+			{
+				try
+				{
+					if (fos != null)
+						fos.close();
+					if (oo != null)
+						oo.close();
+				}
+				catch (IOException e)
+				{
+					throw new RuntimeException(e);
+				}
+			}
+		}
+
+		private Object fromFile(File file)
+		{
+			FileInputStream fis = null;
+			ObjectInput oi = null;
+			try
+			{
+				fis = new FileInputStream(file);
+				oi = new ObjectInputStream(fis);
+				return oi.readObject();
+			}
+			catch (IOException e)
+			{
+				throw new RuntimeException(e);
+			}
+			catch (ClassNotFoundException e)
+			{
+				throw new RuntimeException(e);
+			}
+			finally
+			{
+				try
+				{
+					if (fis != null)
+						fis.close();
+					if (oi != null)
+						oi.close();
+				}
+				catch (IOException e)
+				{
+					throw new RuntimeException(e);
+				}
+			}
+		}
+
+		@Override
+		public void destroy()
+		{
+		}
+
+		@Override
+		public IManageablePage getPage(String sessionId, int pageId)
+		{
+			return (IManageablePage)fromFile(getPageFile(sessionId, pageId));
+		}
+
+		@Override
+		public void removePage(String sessionId, int pageId)
+		{
+		}
+
+		@Override
+		public void storePage(String sessionId, IManageablePage page)
+		{
+			toFile(page, getPageFile(sessionId, page.getPageId()));
+		}
+
+		@Override
+		public void unbind(String sessionId)
+		{
+		}
+
+		@Override
+		public Serializable prepareForSerialization(String sessionId, Serializable page)
+		{
+			return null;
+		}
+
+		@Override
+		public Object restoreAfterSerialization(Serializable serializable)
+		{
+			return null;
+		}
+
+		@Override
+		public IManageablePage convertToPage(Object page)
+		{
+			return null;
+		}
+	}
+
+}


[09/10] wicket git commit: WICKET-6177 Introduce AsynchronousPageStore

Posted by mg...@apache.org.
WICKET-6177 Introduce AsynchronousPageStore

Minor cleanups


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

Branch: refs/heads/master
Commit: 25fb5a29dbe523d6ebd7dccdea639eaf5bc28618
Parents: a4e28b8
Author: Martin Tzvetanov Grigorov <mg...@apache.org>
Authored: Wed Apr 12 23:25:05 2017 +0200
Committer: Martin Tzvetanov Grigorov <mg...@apache.org>
Committed: Wed Apr 12 23:25:05 2017 +0200

----------------------------------------------------------------------
 .../wicket/DefaultPageManagerProvider.java      |   3 +-
 .../wicket/pageStore/AsynchronousDataStore.java |  23 +-
 .../wicket/pageStore/AsynchronousPageStore.java | 100 +++----
 .../wicket/pageStore/PerSessionPageStore.java   |   1 -
 .../pageStore/AsynchronousPageStoreTest.java    | 291 +++----------------
 5 files changed, 88 insertions(+), 330 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/25fb5a29/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 d7b0b45..4b9b130 100644
--- a/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
+++ b/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
@@ -73,7 +73,9 @@ public class DefaultPageManagerProvider implements IPageManagerProvider
 			}
 		}
 		else
+		{
 			pageStore = newPageStore(dataStore);
+		}
 
 		return new PageStoreManager(application.getName(), pageStore, pageManagerContext);
 
@@ -84,7 +86,6 @@ 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/25fb5a29/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousDataStore.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousDataStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousDataStore.java
index e98eb64..7ccd689 100644
--- a/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousDataStore.java
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousDataStore.java
@@ -88,18 +88,15 @@ public class AsynchronousDataStore implements IDataStore
 	public AsynchronousDataStore(final IDataStore dataStore, final int capacity)
 	{
 		this.dataStore = dataStore;
-		entries = new LinkedBlockingQueue<Entry>(capacity);
-		entryMap = new ConcurrentHashMap<String, Entry>();
+		entries = new LinkedBlockingQueue<>(capacity);
+		entryMap = new ConcurrentHashMap<>();
 
 		PageSavingRunnable savingRunnable = new PageSavingRunnable(dataStore, entries, entryMap);
-		pageSavingThread = new Thread(savingRunnable, "Wicket-PageSavingThread");
+		pageSavingThread = new Thread(savingRunnable, "Wicket-AsyncDataStore-PageSavingThread");
 		pageSavingThread.setDaemon(true);
 		pageSavingThread.start();
 	}
 
-	/**
-	 * @see org.apache.wicket.pageStore.IDataStore#destroy()
-	 */
 	@Override
 	public void destroy()
 	{
@@ -130,9 +127,6 @@ public class AsynchronousDataStore implements IDataStore
 		return entryMap.get(getKey(sessionId, id));
 	}
 
-	/**
-	 * @see org.apache.wicket.pageStore.IDataStore#getData(java.lang.String, int)
-	 */
 	@Override
 	public byte[] getData(final String sessionId, final int id)
 	{
@@ -152,18 +146,12 @@ public class AsynchronousDataStore implements IDataStore
 		return data;
 	}
 
-	/**
-	 * @see org.apache.wicket.pageStore.IDataStore#isReplicated()
-	 */
 	@Override
 	public boolean isReplicated()
 	{
 		return dataStore.isReplicated();
 	}
 
-	/**
-	 * @see org.apache.wicket.pageStore.IDataStore#removeData(java.lang.String, int)
-	 */
 	@Override
 	public void removeData(final String sessionId, final int id)
 	{
@@ -180,9 +168,6 @@ public class AsynchronousDataStore implements IDataStore
 		dataStore.removeData(sessionId, id);
 	}
 
-	/**
-	 * @see org.apache.wicket.pageStore.IDataStore#removeData(java.lang.String)
-	 */
 	@Override
 	public void removeData(final String sessionId)
 	{
@@ -362,7 +347,7 @@ public class AsynchronousDataStore implements IDataStore
 	@Override
 	public final boolean canBeAsynchronous()
 	{
-		// should not wrap in abother AsynchronousDataStore
+		// should not wrap in another AsynchronousDataStore
 		return false;
 	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/25fb5a29/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousPageStore.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousPageStore.java
index 3c77df6..43993ba 100644
--- a/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousPageStore.java
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousPageStore.java
@@ -1,3 +1,19 @@
+/*
+ * 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;
@@ -8,7 +24,6 @@ import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.wicket.page.IManageablePage;
-import org.apache.wicket.pageStore.IPageStore;
 import org.apache.wicket.util.lang.Args;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -53,7 +68,7 @@ public class AsynchronousPageStore implements IPageStore
 	/**
 	 * The wrapped {@link IPageStore} that actually stores that pages
 	 */
-	private final IPageStore pageStore;
+	private final IPageStore delegate;
 
 	/**
 	 * The queue where the entries which have to be saved are temporary stored
@@ -69,19 +84,19 @@ public class AsynchronousPageStore implements IPageStore
 	/**
 	 * Construct.
 	 * 
-	 * @param pageStore
+	 * @param delegate
 	 *            the wrapped {@link IPageStore} that actually saved the page
 	 * @param capacity
 	 *            the capacity of the queue that delays the saving
 	 */
-	public AsynchronousPageStore(final IPageStore pageStore, final int capacity)
+	public AsynchronousPageStore(final IPageStore delegate, final int capacity)
 	{
-		this.pageStore = pageStore;
-		entries = new LinkedBlockingQueue<Entry>(capacity);
-		entryMap = new ConcurrentHashMap<String, Entry>();
+		this.delegate = Args.notNull(delegate, "delegate");
+		entries = new LinkedBlockingQueue<>(capacity);
+		entryMap = new ConcurrentHashMap<>();
 
-		PageSavingRunnable savingRunnable = new PageSavingRunnable(pageStore, entries, entryMap);
-		pageSavingThread = new Thread(savingRunnable, "AsyncPageStore-PageSavingThread");
+		PageSavingRunnable savingRunnable = new PageSavingRunnable(delegate, entries, entryMap);
+		pageSavingThread = new Thread(savingRunnable, "Wicket-AsyncPageStore-PageSavingThread");
 		pageSavingThread.setDaemon(true);
 		pageSavingThread.start();
 	}
@@ -139,7 +154,7 @@ public class AsynchronousPageStore implements IPageStore
 			final int prime = 31;
 			int result = 1;
 			result = prime * result + page.getPageId();
-			result = prime * result + ((sessionId == null) ? 0 : sessionId.hashCode());
+			result = prime * result + sessionId.hashCode();
 			return result;
 		}
 
@@ -155,12 +170,7 @@ public class AsynchronousPageStore implements IPageStore
 			Entry other = (Entry)obj;
 			if (page.getPageId() != other.page.getPageId())
 				return false;
-			if (sessionId == null)
-			{
-				if (other.sessionId != null)
-					return false;
-			}
-			else if (!sessionId.equals(other.sessionId))
+			if (!sessionId.equals(other.sessionId))
 				return false;
 			return true;
 		}
@@ -184,12 +194,12 @@ public class AsynchronousPageStore implements IPageStore
 
 		private final ConcurrentMap<String, Entry> entryMap;
 
-		private final IPageStore pageStore;
+		private final IPageStore delegate;
 
-		private PageSavingRunnable(IPageStore pageStore, BlockingQueue<Entry> entries,
-			ConcurrentMap<String, Entry> entryMap)
+		private PageSavingRunnable(IPageStore delegate, BlockingQueue<Entry> entries,
+		                           ConcurrentMap<String, Entry> entryMap)
 		{
-			this.pageStore = pageStore;
+			this.delegate = delegate;
 			this.entries = entries;
 			this.entryMap = entryMap;
 		}
@@ -212,16 +222,13 @@ public class AsynchronousPageStore implements IPageStore
 				if (entry != null)
 				{
 					log.debug("Saving asynchronously: {}...", entry);
-					pageStore.storePage(entry.sessionId, entry.page);
+					delegate.storePage(entry.sessionId, entry.page);
 					entryMap.remove(getKey(entry));
 				}
 			}
 		}
 	}
 
-	/**
-	 * @see org.apache.wicket.pageStore.IPageStore#destroy()
-	 */
 	@Override
 	public void destroy()
 	{
@@ -238,12 +245,9 @@ public class AsynchronousPageStore implements IPageStore
 			}
 		}
 
-		pageStore.destroy();
+		delegate.destroy();
 	}
 
-	/**
-	 * @see org.apache.wicket.pageStore.IPageStore#getPage(java.lang.String, int)
-	 */
 	@Override
 	public IManageablePage getPage(String sessionId, int pageId)
 	{
@@ -255,7 +259,7 @@ public class AsynchronousPageStore implements IPageStore
 				sessionId, pageId);
 			return entry.page;
 		}
-		IManageablePage page = pageStore.getPage(sessionId, pageId);
+		IManageablePage page = delegate.getPage(sessionId, pageId);
 
 		log.debug("Returning the page of a stored entry with session id '{}' and page id '{}'",
 			sessionId, pageId);
@@ -263,9 +267,6 @@ public class AsynchronousPageStore implements IPageStore
 		return page;
 	}
 
-	/**
-	 * @see org.apache.wicket.pageStore.IPageStore#removePage(java.lang.String, int)
-	 */
 	@Override
 	public void removePage(String sessionId, int pageId)
 	{
@@ -279,14 +280,9 @@ public class AsynchronousPageStore implements IPageStore
 			}
 		}
 
-		pageStore.removePage(sessionId, pageId);
-
+		delegate.removePage(sessionId, pageId);
 	}
 
-	/**
-	 * @see org.apache.wicket.pageStore.IPageStore#storePage(java.lang.String,
-	 *      org.apache.wicket.page.IManageablePage)
-	 */
 	@Override
 	public void storePage(String sessionId, IManageablePage page)
 	{
@@ -306,59 +302,45 @@ public class AsynchronousPageStore implements IPageStore
 				log.debug("Storing synchronously page with id '{}' in session '{}'",
 					page.getPageId(), sessionId);
 				entryMap.remove(key);
-				pageStore.storePage(sessionId, page);
+				delegate.storePage(sessionId, page);
 			}
 		}
 		catch (InterruptedException e)
 		{
 			log.error(e.getMessage(), e);
 			entryMap.remove(key);
-			pageStore.storePage(sessionId, page);
+			delegate.storePage(sessionId, page);
 		}
-
 	}
 
-	/**
-	 * @see org.apache.wicket.pageStore.IPageStore#unbind(java.lang.String)
-	 */
 	@Override
 	public void unbind(String sessionId)
 	{
-		pageStore.unbind(sessionId);
+		delegate.unbind(sessionId);
 	}
 
-	/**
-	 * @see org.apache.wicket.pageStore.IPageStore#prepareForSerialization(java.lang. String,
-	 *      java.io.Serializable)
-	 */
 	@Override
 	public Serializable prepareForSerialization(String sessionId, Serializable page)
 	{
-		return pageStore.prepareForSerialization(sessionId, page);
+		return delegate.prepareForSerialization(sessionId, page);
 	}
 
-	/**
-	 * @see org.apache.wicket.pageStore.IPageStore#restoreAfterSerialization(java.io. Serializable)
-	 */
 	@Override
 	public Object restoreAfterSerialization(Serializable serializable)
 	{
-		return pageStore.restoreAfterSerialization(serializable);
+		return delegate.restoreAfterSerialization(serializable);
 	}
 
-	/**
-	 * @see org.apache.wicket.pageStore.IPageStore#convertToPage(java.lang.Object)
-	 */
 	@Override
 	public IManageablePage convertToPage(Object page)
 	{
-		return pageStore.convertToPage(page);
+		return delegate.convertToPage(page);
 	}
 
 	@Override
 	public boolean canBeAsynchronous()
 	{
+		// should not wrap in another AsynchronousPageStore
 		return false;
 	}
-
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/25fb5a29/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
index abef0c9..4a21f4c 100644
--- a/wicket-core/src/main/java/org/apache/wicket/pageStore/PerSessionPageStore.java
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/PerSessionPageStore.java
@@ -323,7 +323,6 @@ public class PerSessionPageStore extends AbstractCachingPageStore<IManageablePag
 			cache.clear();
 		}
 	}
-	
 
 	@Override
 	public boolean canBeAsynchronous()

http://git-wip-us.apache.org/repos/asf/wicket/blob/25fb5a29/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java b/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java
index 7ade857..4b17f69 100644
--- a/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java
@@ -1,3 +1,19 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
@@ -8,44 +24,34 @@ import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutput;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import com.google.common.base.Stopwatch;
 import org.apache.commons.lang3.RandomUtils;
 import org.apache.wicket.page.IManageablePage;
 import org.apache.wicket.serialize.ISerializer;
 import org.apache.wicket.serialize.java.DeflatedJavaSerializer;
+import org.apache.wicket.util.SlowTests;
 import org.apache.wicket.util.file.File;
 import org.apache.wicket.util.lang.Bytes;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Stopwatch;
-
 
 /**
  * AsynchronousPageStoreTest
- * 
- * @author manuelbarzi
  *
+ * @author manuelbarzi
  */
+@Category(SlowTests.class)
 public class AsynchronousPageStoreTest
 {
-
 	/** Log for reporting. */
 	private static final Logger log = LoggerFactory.getLogger(AsynchronousPageStoreTest.class);
 
@@ -96,7 +102,7 @@ public class AsynchronousPageStoreTest
 		private void writeObject(java.io.ObjectOutputStream s) throws IOException
 		{
 			log.debug("serializing page {} for {}ms (session {})", getPageId(), writeMillis,
-				sessionId);
+					sessionId);
 			try
 			{
 				Thread.sleep(writeMillis);
@@ -113,10 +119,10 @@ public class AsynchronousPageStoreTest
 		}
 
 		private void readObject(java.io.ObjectInputStream s)
-			throws IOException, ClassNotFoundException
+				throws IOException, ClassNotFoundException
 		{
 			log.debug("deserializing page {} for {}ms (session {})", getPageId(), writeMillis,
-				sessionId);
+					sessionId);
 			try
 			{
 				Thread.sleep(readMillis);
@@ -135,15 +141,15 @@ public class AsynchronousPageStoreTest
 		public String toString()
 		{
 			return "DummyPage[pageId = " + pageId + ", writeMillis = " + writeMillis +
-				", readMillis = " + readMillis + ", sessionId = " + sessionId + ", hashCode = " +
-				hashCode() + "]";
+					", readMillis = " + readMillis + ", sessionId = " + sessionId + ", hashCode = " +
+					hashCode() + "]";
 		}
 	}
 
 	/**
 	 * Store returns the same page instance from queue when there is a close request for it back
 	 * again.
-	 * 
+	 *
 	 * @throws InterruptedException
 	 */
 	@Test
@@ -154,7 +160,7 @@ public class AsynchronousPageStoreTest
 		// ISerializer serializer = new DummySerializer();
 
 		IDataStore dataStore = new DiskDataStore("applicationName", new File("./target"),
-			Bytes.bytes(10000l));
+				Bytes.bytes(10000l));
 
 		// IPageStore pageStore = new DummyPageStore(new File("target/store"));
 		IPageStore pageStore = spy(new DefaultPageStore(serializer, dataStore, 0));
@@ -179,7 +185,7 @@ public class AsynchronousPageStoreTest
 	/**
 	 * Store returns the restored page instance from wrapped store when there is a distant request
 	 * for it back again.
-	 * 
+	 *
 	 * @throws InterruptedException
 	 */
 	@Test
@@ -190,7 +196,7 @@ public class AsynchronousPageStoreTest
 		// ISerializer serializer = new DummySerializer();
 
 		IDataStore dataStore = new DiskDataStore("applicationName", new File("./target"),
-			Bytes.bytes(10000l));
+				Bytes.bytes(10000l));
 
 		// IPageStore pageStore = new DummyPageStore(new File("target/store"));
 		IPageStore pageStore = spy(new DefaultPageStore(serializer, dataStore, 0));
@@ -215,7 +221,7 @@ public class AsynchronousPageStoreTest
 	/**
 	 * Store works fully asynchronous when number of pages handled never exceeds the
 	 * asynchronous-storage capacity.
-	 * 
+	 *
 	 * @throws InterruptedException
 	 */
 	@Test
@@ -228,7 +234,7 @@ public class AsynchronousPageStoreTest
 		int asyncPageStoreCapacity = pages * sessions;
 
 		List<Metrics> results = runTest(sessions, pages, writeMillis, readMillis,
-			asyncPageStoreCapacity);
+				asyncPageStoreCapacity);
 
 		for (Metrics metrics : results)
 			System.out.println(metrics);
@@ -244,7 +250,7 @@ public class AsynchronousPageStoreTest
 	/**
 	 * Store behaves sync from when number of pages handled exceeds the given asynchronous-storage
 	 * capacity. It works asynchronous until the number of pages reaches the limit (capacity).
-	 * 
+	 *
 	 * @throws InterruptedException
 	 */
 	@Test
@@ -255,10 +261,10 @@ public class AsynchronousPageStoreTest
 		long writeMillis = 2000;
 		long readMillis = 1500;
 		int asyncPageStoreCapacity = pages; // only up to the first round of
-											// pages
+		// pages
 
 		List<Metrics> results = runTest(sessions, pages, writeMillis, readMillis,
-			asyncPageStoreCapacity);
+				asyncPageStoreCapacity);
 
 		for (Metrics metrics : results)
 			System.out.println(metrics);
@@ -294,12 +300,12 @@ public class AsynchronousPageStoreTest
 		public String toString()
 		{
 			return "Metrics[storedPage = " + storedPage + ", storingMillis = " + storingMillis +
-				", restoredPage = " + restoredPage + ", restoringMillis = " + restoringMillis + "]";
+					", restoredPage = " + restoredPage + ", restoringMillis = " + restoringMillis + "]";
 		}
 	}
 
 	private List<Metrics> runTest(int sessions, int pages, long writeMillis, long readMillis,
-		int asyncPageStoreCapacity) throws InterruptedException
+	                              int asyncPageStoreCapacity) throws InterruptedException
 	{
 
 		List<Metrics> results = new ArrayList<>();
@@ -310,7 +316,7 @@ public class AsynchronousPageStoreTest
 		ISerializer serializer = new DeflatedJavaSerializer("applicationKey");
 
 		IDataStore dataStore = new DiskDataStore("applicationName", new File("./target"),
-			Bytes.bytes(10000l));
+				Bytes.bytes(10000l));
 
 		// IPageStore pageStore = new DummyPageStore(new File("target/store")) {
 		IPageStore pageStore = new DefaultPageStore(serializer, dataStore, 0)
@@ -339,7 +345,7 @@ public class AsynchronousPageStoreTest
 
 				stopwatch.reset();
 				DummyPage page = new DummyPage(pageId, around(writeMillis), around(readMillis),
-					sessionId);
+						sessionId);
 				stopwatch.start();
 				asyncPageStore.storePage(sessionId, page);
 				metrics.storedPage = page;
@@ -348,7 +354,7 @@ public class AsynchronousPageStoreTest
 				stopwatch.reset();
 				stopwatch.start();
 				metrics.restoredPage = DummyPage.class
-					.cast(asyncPageStore.getPage(sessionId, pageId));
+						.cast(asyncPageStore.getPage(sessionId, pageId));
 				metrics.restoringMillis = stopwatch.elapsed(TimeUnit.MILLISECONDS);
 
 				results.add(metrics);
@@ -364,219 +370,4 @@ public class AsynchronousPageStoreTest
 	{
 		return RandomUtils.nextLong((long)(target * .9), (long)(target * 1.1));
 	}
-
-	// other aux dummy impls for testing
-
-	private class DummySerializer implements ISerializer
-	{
-
-		@Override
-		public byte[] serialize(Object obj)
-		{
-			ByteArrayOutputStream bos = null;
-			ObjectOutput out = null;
-			try
-			{
-				bos = new ByteArrayOutputStream();
-				out = new ObjectOutputStream(bos);
-				out.writeObject(obj);
-				return bos.toByteArray();
-			}
-			catch (FileNotFoundException e)
-			{
-				throw new RuntimeException(e);
-			}
-			catch (IOException e)
-			{
-				throw new RuntimeException(e);
-			}
-			finally
-			{
-				try
-				{
-					if (bos != null)
-						bos.close();
-					if (out != null)
-						out.close();
-				}
-				catch (IOException e)
-				{
-					throw new RuntimeException(e);
-				}
-			}
-		}
-
-		@Override
-		public Object deserialize(byte[] bytes)
-		{
-			ByteArrayInputStream bis = null;
-			ObjectInput in = null;
-			try
-			{
-				bis = new ByteArrayInputStream(bytes);
-				in = new ObjectInputStream(bis);
-				return in.readObject();
-			}
-			catch (IOException e)
-			{
-				throw new RuntimeException(e);
-			}
-			catch (ClassNotFoundException e)
-			{
-				throw new RuntimeException(e);
-			}
-			finally
-			{
-				try
-				{
-					if (bis != null)
-						bis.close();
-					if (in != null)
-						in.close();
-				}
-				catch (IOException e)
-				{
-					throw new RuntimeException(e);
-				}
-			}
-		}
-
-	}
-
-	private class DummyPageStore implements IPageStore
-	{
-
-		private File folder;
-
-		private DummyPageStore(File folder)
-		{
-			folder.mkdirs();
-			this.folder = folder;
-		}
-
-		private File getPageFile(String sessionId, int pageId)
-		{
-			return new File(folder.getAbsolutePath() + "/" + sessionId + "-" + pageId + ".page");
-		}
-
-		private void toFile(Object obj, File file)
-		{
-			FileOutputStream fos = null;
-			ObjectOutput oo = null;
-			try
-			{
-				fos = new FileOutputStream(file);
-				oo = new ObjectOutputStream(fos);
-				oo.writeObject(obj);
-			}
-			catch (FileNotFoundException e)
-			{
-				throw new RuntimeException(e);
-			}
-			catch (IOException e)
-			{
-				throw new RuntimeException(e);
-			}
-			finally
-			{
-				try
-				{
-					if (fos != null)
-						fos.close();
-					if (oo != null)
-						oo.close();
-				}
-				catch (IOException e)
-				{
-					throw new RuntimeException(e);
-				}
-			}
-		}
-
-		private Object fromFile(File file)
-		{
-			FileInputStream fis = null;
-			ObjectInput oi = null;
-			try
-			{
-				fis = new FileInputStream(file);
-				oi = new ObjectInputStream(fis);
-				return oi.readObject();
-			}
-			catch (IOException e)
-			{
-				throw new RuntimeException(e);
-			}
-			catch (ClassNotFoundException e)
-			{
-				throw new RuntimeException(e);
-			}
-			finally
-			{
-				try
-				{
-					if (fis != null)
-						fis.close();
-					if (oi != null)
-						oi.close();
-				}
-				catch (IOException e)
-				{
-					throw new RuntimeException(e);
-				}
-			}
-		}
-
-		@Override
-		public void destroy()
-		{
-		}
-
-		@Override
-		public IManageablePage getPage(String sessionId, int pageId)
-		{
-			return (IManageablePage)fromFile(getPageFile(sessionId, pageId));
-		}
-
-		@Override
-		public void removePage(String sessionId, int pageId)
-		{
-		}
-
-		@Override
-		public void storePage(String sessionId, IManageablePage page)
-		{
-			toFile(page, getPageFile(sessionId, page.getPageId()));
-		}
-
-		@Override
-		public void unbind(String sessionId)
-		{
-		}
-
-		@Override
-		public Serializable prepareForSerialization(String sessionId, Serializable page)
-		{
-			return null;
-		}
-
-		@Override
-		public Object restoreAfterSerialization(Serializable serializable)
-		{
-			return null;
-		}
-
-		@Override
-		public IManageablePage convertToPage(Object page)
-		{
-			return null;
-		}
-
-		@Override
-		public boolean canBeAsynchronous()
-		{
-			return false;
-		}
-	}
-
-}
\ No newline at end of file
+}


[02/10] wicket git commit: adjust format & doc

Posted by mg...@apache.org.
adjust format & doc


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

Branch: refs/heads/master
Commit: 0e975d729c9dd85dc3438601a6901893bf0df121
Parents: 2ffd587
Author: Manuel Barzi <ma...@Manuels-MacBook-Pro.local>
Authored: Wed Mar 15 16:26:10 2017 +0100
Committer: Manuel Barzi <ma...@Manuels-MacBook-Pro.local>
Committed: Wed Mar 15 16:26:10 2017 +0100

----------------------------------------------------------------------
 .../apache/wicket/pageStore/AsyncPageStore.java | 373 --------------
 .../wicket/pageStore/AsynchronousPageStore.java | 358 +++++++++++++
 .../wicket/pageStore/AsyncPageStoreTest.java    | 497 ------------------
 .../pageStore/AsynchronousPageStoreTest.java    | 498 +++++++++++++++++++
 4 files changed, 856 insertions(+), 870 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/0e975d72/wicket-core/src/main/java/org/apache/wicket/pageStore/AsyncPageStore.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/AsyncPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/AsyncPageStore.java
deleted file mode 100644
index 213164d..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/pageStore/AsyncPageStore.java
+++ /dev/null
@@ -1,373 +0,0 @@
-package org.apache.wicket.pageStore;
-
-import java.io.Serializable;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.wicket.page.IManageablePage;
-import org.apache.wicket.util.lang.Args;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Facade for {@link IPageStore} that does the actual saving in worker thread.
- * <p>
- * Creates an {@link Entry} for each double (sessionId, page) and puts it in {@link #entries} queue
- * if there is room. Acts as producer.<br/>
- * Later {@link PageSavingRunnable} reads in blocking manner from {@link #entries} and saves each
- * entry. Acts as consumer.
- * </p>
- * It starts only one instance of {@link PageSavingRunnable} because all we need is to make the page
- * storing asynchronous. We don't want to write concurrently in the wrapped {@link IPageStore},
- * though it may happen in the extreme case when the queue is full. These cases should be avoided.
- * 
- * Based on AsynchronousDataStore (@author Matej Knopp).
- * 
- * @author manuelbarzi
- */
-public class AsyncPageStore implements IPageStore
-{
-
-	/** Log for reporting. */
-	private static final Logger log = LoggerFactory.getLogger(AsyncPageStore.class);
-
-	/**
-	 * The time to wait when adding an {@link Entry} into the entries. In millis.
-	 */
-	private static final long OFFER_WAIT = 30L;
-
-	/**
-	 * The time to wait for an entry to save with the wrapped {@link IPageStore} . In millis.
-	 */
-	private static final long POLL_WAIT = 1000L;
-
-	/**
-	 * The page saving thread.
-	 */
-	private final Thread pageSavingThread;
-
-	/**
-	 * The wrapped {@link IPageStore} that actually stores that pages
-	 */
-	private final IPageStore pageStore;
-
-	/**
-	 * The queue where the entries which have to be saved are temporary stored
-	 */
-	private final BlockingQueue<Entry> entries;
-
-	/**
-	 * A map 'sessionId:::pageId' -> {@link Entry}. Used for fast retrieval of {@link Entry}s which
-	 * are not yet stored by the wrapped {@link IPageStore}
-	 */
-	private final ConcurrentMap<String, Entry> entryMap;
-
-	/**
-	 * Construct.
-	 * 
-	 * @param pageStore
-	 *            the wrapped {@link IPageStore} that actually saved the page
-	 * @param capacity
-	 *            the capacity of the queue that delays the saving
-	 */
-	public AsyncPageStore(final IPageStore pageStore, final int capacity)
-	{
-		this.pageStore = pageStore;
-		entries = new LinkedBlockingQueue<Entry>(capacity);
-		entryMap = new ConcurrentHashMap<String, Entry>();
-
-		PageSavingRunnable savingRunnable = new PageSavingRunnable(pageStore, entries, entryMap);
-		pageSavingThread = new Thread(savingRunnable, "AsyncPageStore-PageSavingThread");
-		pageSavingThread.setDaemon(true);
-		pageSavingThread.start();
-	}
-
-	/**
-	 * Little helper
-	 * 
-	 * @param sessionId
-	 * @param pageId
-	 * @return Entry
-	 */
-	private Entry getEntry(final String sessionId, final int pageId)
-	{
-		return entryMap.get(getKey(sessionId, pageId));
-	}
-
-	/**
-	 * 
-	 * @param pageId
-	 * @param sessionId
-	 * @return generated key
-	 */
-	private static String getKey(final String sessionId, final int pageId)
-	{
-		return pageId + ":::" + sessionId;
-	}
-
-	/**
-	 * 
-	 * @param entry
-	 * @return generated key
-	 */
-	private static String getKey(final Entry entry)
-	{
-		return getKey(entry.sessionId, entry.page.getPageId());
-	}
-
-	/**
-	 * The structure used for an entry in the queue
-	 */
-	private static class Entry
-	{
-		private final String sessionId;
-		private final IManageablePage page;
-
-		public Entry(final String sessionId, final IManageablePage page)
-		{
-			this.sessionId = Args.notNull(sessionId, "sessionId");
-			this.page = Args.notNull(page, "page");
-		}
-
-		@Override
-		public int hashCode()
-		{
-			final int prime = 31;
-			int result = 1;
-			result = prime * result + page.getPageId();
-			result = prime * result + ((sessionId == null) ? 0 : sessionId.hashCode());
-			return result;
-		}
-
-		@Override
-		public boolean equals(Object obj)
-		{
-			if (this == obj)
-				return true;
-			if (obj == null)
-				return false;
-			if (getClass() != obj.getClass())
-				return false;
-			Entry other = (Entry)obj;
-			if (page.getPageId() != other.page.getPageId())
-				return false;
-			if (sessionId == null)
-			{
-				if (other.sessionId != null)
-					return false;
-			}
-			else if (!sessionId.equals(other.sessionId))
-				return false;
-			return true;
-		}
-
-		@Override
-		public String toString()
-		{
-			return "Entry [sessionId=" + sessionId + ", pageId=" + page.getPageId() + "]";
-		}
-
-	}
-
-	/**
-	 * The thread that acts as consumer of {@link Entry}ies
-	 */
-	private static class PageSavingRunnable implements Runnable
-	{
-		private static final Logger log = LoggerFactory.getLogger(PageSavingRunnable.class);
-
-		private final BlockingQueue<Entry> entries;
-
-		private final ConcurrentMap<String, Entry> entryMap;
-
-		private final IPageStore pageStore;
-
-		private PageSavingRunnable(IPageStore pageStore, BlockingQueue<Entry> entries,
-			ConcurrentMap<String, Entry> entryMap)
-		{
-			this.pageStore = pageStore;
-			this.entries = entries;
-			this.entryMap = entryMap;
-		}
-
-		@Override
-		public void run()
-		{
-			while (!Thread.interrupted())
-			{
-				Entry entry = null;
-				try
-				{
-					entry = entries.poll(POLL_WAIT, TimeUnit.MILLISECONDS);
-				}
-				catch (InterruptedException e)
-				{
-					Thread.currentThread().interrupt();
-				}
-
-				if (entry != null)
-				{
-					log.debug("Saving asynchronously: {}...", entry);
-					pageStore.storePage(entry.sessionId, entry.page);
-					entryMap.remove(getKey(entry));
-				}
-			}
-		}
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see org.apache.wicket.pageStore.IPageStore#destroy()
-	 */
-	@Override
-	public void destroy()
-	{
-		if (pageSavingThread.isAlive())
-		{
-			pageSavingThread.interrupt();
-			try
-			{
-				pageSavingThread.join();
-			}
-			catch (InterruptedException e)
-			{
-				log.error(e.getMessage(), e);
-			}
-		}
-
-		pageStore.destroy();
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see org.apache.wicket.pageStore.IPageStore#getPage(java.lang.String, int)
-	 */
-	@Override
-	public IManageablePage getPage(String sessionId, int pageId)
-	{
-		Entry entry = getEntry(sessionId, pageId);
-		if (entry != null)
-		{
-			log.debug(
-				"Returning the page of a non-stored entry with session id '{}' and page id '{}'",
-				sessionId, pageId);
-			return entry.page;
-		}
-		IManageablePage page = pageStore.getPage(sessionId, pageId);
-
-		log.debug("Returning the page of a stored entry with session id '{}' and page id '{}'",
-			sessionId, pageId);
-
-		return page;
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see org.apache.wicket.pageStore.IPageStore#removePage(java.lang.String, int)
-	 */
-	@Override
-	public void removePage(String sessionId, int pageId)
-	{
-		String key = getKey(sessionId, pageId);
-		if (key != null)
-		{
-			Entry entry = entryMap.remove(key);
-			if (entry != null)
-			{
-				entries.remove(entry);
-			}
-		}
-
-		pageStore.removePage(sessionId, pageId);
-
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see org.apache.wicket.pageStore.IPageStore#storePage(java.lang.String,
-	 * org.apache.wicket.page.IManageablePage)
-	 */
-	@Override
-	public void storePage(String sessionId, IManageablePage page)
-	{
-		Entry entry = new Entry(sessionId, page);
-		String key = getKey(entry);
-		entryMap.put(key, entry);
-
-		try
-		{
-			if (entries.offer(entry, OFFER_WAIT, TimeUnit.MILLISECONDS))
-			{
-				log.debug("Offered for storing asynchronously page with id '{}' in session '{}'",
-					page.getPageId(), sessionId);
-			}
-			else
-			{
-				log.debug("Storing synchronously page with id '{}' in session '{}'",
-					page.getPageId(), sessionId);
-				entryMap.remove(key);
-				pageStore.storePage(sessionId, page);
-			}
-		}
-		catch (InterruptedException e)
-		{
-			log.error(e.getMessage(), e);
-			entryMap.remove(key);
-			pageStore.storePage(sessionId, page);
-		}
-
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see org.apache.wicket.pageStore.IPageStore#unbind(java.lang.String)
-	 */
-	@Override
-	public void unbind(String sessionId)
-	{
-		pageStore.unbind(sessionId);
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see org.apache.wicket.pageStore.IPageStore#prepareForSerialization(java.lang. String,
-	 * java.io.Serializable)
-	 */
-	@Override
-	public Serializable prepareForSerialization(String sessionId, Serializable page)
-	{
-		return pageStore.prepareForSerialization(sessionId, page);
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see org.apache.wicket.pageStore.IPageStore#restoreAfterSerialization(java.io. Serializable)
-	 */
-	@Override
-	public Object restoreAfterSerialization(Serializable serializable)
-	{
-		return pageStore.restoreAfterSerialization(serializable);
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see org.apache.wicket.pageStore.IPageStore#convertToPage(java.lang.Object)
-	 */
-	@Override
-	public IManageablePage convertToPage(Object page)
-	{
-		return pageStore.convertToPage(page);
-	}
-
-}

http://git-wip-us.apache.org/repos/asf/wicket/blob/0e975d72/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousPageStore.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousPageStore.java
new file mode 100644
index 0000000..087257c
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousPageStore.java
@@ -0,0 +1,358 @@
+package org.apache.wicket.pageStore;
+
+import java.io.Serializable;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.wicket.page.IManageablePage;
+import org.apache.wicket.pageStore.IPageStore;
+import org.apache.wicket.util.lang.Args;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Facade for {@link IPageStore} that does the actual saving in worker thread.
+ * <p>
+ * Creates an {@link Entry} for each double (sessionId, page) and puts it in {@link #entries} queue
+ * if there is room. Acts as producer.<br/>
+ * Later {@link PageSavingRunnable} reads in blocking manner from {@link #entries} and saves each
+ * entry. Acts as consumer.
+ * </p>
+ * It starts only one instance of {@link PageSavingRunnable} because all we need is to make the page
+ * storing asynchronous. We don't want to write concurrently in the wrapped {@link IPageStore},
+ * though it may happen in the extreme case when the queue is full. These cases should be avoided.
+ * 
+ * Based on AsynchronousDataStore (@author Matej Knopp).
+ * 
+ * @author manuelbarzi
+ */
+public class AsynchronousPageStore implements IPageStore
+{
+
+	/** Log for reporting. */
+	private static final Logger log = LoggerFactory.getLogger(AsynchronousPageStore.class);
+
+	/**
+	 * The time to wait when adding an {@link Entry} into the entries. In millis.
+	 */
+	private static final long OFFER_WAIT = 30L;
+
+	/**
+	 * The time to wait for an entry to save with the wrapped {@link IPageStore} . In millis.
+	 */
+	private static final long POLL_WAIT = 1000L;
+
+	/**
+	 * The page saving thread.
+	 */
+	private final Thread pageSavingThread;
+
+	/**
+	 * The wrapped {@link IPageStore} that actually stores that pages
+	 */
+	private final IPageStore pageStore;
+
+	/**
+	 * The queue where the entries which have to be saved are temporary stored
+	 */
+	private final BlockingQueue<Entry> entries;
+
+	/**
+	 * A map 'sessionId:::pageId' -> {@link Entry}. Used for fast retrieval of {@link Entry}s which
+	 * are not yet stored by the wrapped {@link IPageStore}
+	 */
+	private final ConcurrentMap<String, Entry> entryMap;
+
+	/**
+	 * Construct.
+	 * 
+	 * @param pageStore
+	 *            the wrapped {@link IPageStore} that actually saved the page
+	 * @param capacity
+	 *            the capacity of the queue that delays the saving
+	 */
+	public AsynchronousPageStore(final IPageStore pageStore, final int capacity)
+	{
+		this.pageStore = pageStore;
+		entries = new LinkedBlockingQueue<Entry>(capacity);
+		entryMap = new ConcurrentHashMap<String, Entry>();
+
+		PageSavingRunnable savingRunnable = new PageSavingRunnable(pageStore, entries, entryMap);
+		pageSavingThread = new Thread(savingRunnable, "AsyncPageStore-PageSavingThread");
+		pageSavingThread.setDaemon(true);
+		pageSavingThread.start();
+	}
+
+	/**
+	 * Little helper
+	 * 
+	 * @param sessionId
+	 * @param pageId
+	 * @return Entry
+	 */
+	private Entry getEntry(final String sessionId, final int pageId)
+	{
+		return entryMap.get(getKey(sessionId, pageId));
+	}
+
+	/**
+	 * 
+	 * @param pageId
+	 * @param sessionId
+	 * @return generated key
+	 */
+	private static String getKey(final String sessionId, final int pageId)
+	{
+		return pageId + ":::" + sessionId;
+	}
+
+	/**
+	 * 
+	 * @param entry
+	 * @return generated key
+	 */
+	private static String getKey(final Entry entry)
+	{
+		return getKey(entry.sessionId, entry.page.getPageId());
+	}
+
+	/**
+	 * The structure used for an entry in the queue
+	 */
+	private static class Entry
+	{
+		private final String sessionId;
+		private final IManageablePage page;
+
+		public Entry(final String sessionId, final IManageablePage page)
+		{
+			this.sessionId = Args.notNull(sessionId, "sessionId");
+			this.page = Args.notNull(page, "page");
+		}
+
+		@Override
+		public int hashCode()
+		{
+			final int prime = 31;
+			int result = 1;
+			result = prime * result + page.getPageId();
+			result = prime * result + ((sessionId == null) ? 0 : sessionId.hashCode());
+			return result;
+		}
+
+		@Override
+		public boolean equals(Object obj)
+		{
+			if (this == obj)
+				return true;
+			if (obj == null)
+				return false;
+			if (getClass() != obj.getClass())
+				return false;
+			Entry other = (Entry)obj;
+			if (page.getPageId() != other.page.getPageId())
+				return false;
+			if (sessionId == null)
+			{
+				if (other.sessionId != null)
+					return false;
+			}
+			else if (!sessionId.equals(other.sessionId))
+				return false;
+			return true;
+		}
+
+		@Override
+		public String toString()
+		{
+			return "Entry [sessionId=" + sessionId + ", pageId=" + page.getPageId() + "]";
+		}
+
+	}
+
+	/**
+	 * The thread that acts as consumer of {@link Entry}ies
+	 */
+	private static class PageSavingRunnable implements Runnable
+	{
+		private static final Logger log = LoggerFactory.getLogger(PageSavingRunnable.class);
+
+		private final BlockingQueue<Entry> entries;
+
+		private final ConcurrentMap<String, Entry> entryMap;
+
+		private final IPageStore pageStore;
+
+		private PageSavingRunnable(IPageStore pageStore, BlockingQueue<Entry> entries,
+			ConcurrentMap<String, Entry> entryMap)
+		{
+			this.pageStore = pageStore;
+			this.entries = entries;
+			this.entryMap = entryMap;
+		}
+
+		@Override
+		public void run()
+		{
+			while (!Thread.interrupted())
+			{
+				Entry entry = null;
+				try
+				{
+					entry = entries.poll(POLL_WAIT, TimeUnit.MILLISECONDS);
+				}
+				catch (InterruptedException e)
+				{
+					Thread.currentThread().interrupt();
+				}
+
+				if (entry != null)
+				{
+					log.debug("Saving asynchronously: {}...", entry);
+					pageStore.storePage(entry.sessionId, entry.page);
+					entryMap.remove(getKey(entry));
+				}
+			}
+		}
+	}
+
+	/**
+	 * @see org.apache.wicket.pageStore.IPageStore#destroy()
+	 */
+	@Override
+	public void destroy()
+	{
+		if (pageSavingThread.isAlive())
+		{
+			pageSavingThread.interrupt();
+			try
+			{
+				pageSavingThread.join();
+			}
+			catch (InterruptedException e)
+			{
+				log.error(e.getMessage(), e);
+			}
+		}
+
+		pageStore.destroy();
+	}
+
+	/**
+	 * @see org.apache.wicket.pageStore.IPageStore#getPage(java.lang.String, int)
+	 */
+	@Override
+	public IManageablePage getPage(String sessionId, int pageId)
+	{
+		Entry entry = getEntry(sessionId, pageId);
+		if (entry != null)
+		{
+			log.debug(
+				"Returning the page of a non-stored entry with session id '{}' and page id '{}'",
+				sessionId, pageId);
+			return entry.page;
+		}
+		IManageablePage page = pageStore.getPage(sessionId, pageId);
+
+		log.debug("Returning the page of a stored entry with session id '{}' and page id '{}'",
+			sessionId, pageId);
+
+		return page;
+	}
+
+	/**
+	 * @see org.apache.wicket.pageStore.IPageStore#removePage(java.lang.String, int)
+	 */
+	@Override
+	public void removePage(String sessionId, int pageId)
+	{
+		String key = getKey(sessionId, pageId);
+		if (key != null)
+		{
+			Entry entry = entryMap.remove(key);
+			if (entry != null)
+			{
+				entries.remove(entry);
+			}
+		}
+
+		pageStore.removePage(sessionId, pageId);
+
+	}
+
+	/**
+	 * @see org.apache.wicket.pageStore.IPageStore#storePage(java.lang.String,
+	 *      org.apache.wicket.page.IManageablePage)
+	 */
+	@Override
+	public void storePage(String sessionId, IManageablePage page)
+	{
+		Entry entry = new Entry(sessionId, page);
+		String key = getKey(entry);
+		entryMap.put(key, entry);
+
+		try
+		{
+			if (entries.offer(entry, OFFER_WAIT, TimeUnit.MILLISECONDS))
+			{
+				log.debug("Offered for storing asynchronously page with id '{}' in session '{}'",
+					page.getPageId(), sessionId);
+			}
+			else
+			{
+				log.debug("Storing synchronously page with id '{}' in session '{}'",
+					page.getPageId(), sessionId);
+				entryMap.remove(key);
+				pageStore.storePage(sessionId, page);
+			}
+		}
+		catch (InterruptedException e)
+		{
+			log.error(e.getMessage(), e);
+			entryMap.remove(key);
+			pageStore.storePage(sessionId, page);
+		}
+
+	}
+
+	/**
+	 * @see org.apache.wicket.pageStore.IPageStore#unbind(java.lang.String)
+	 */
+	@Override
+	public void unbind(String sessionId)
+	{
+		pageStore.unbind(sessionId);
+	}
+
+	/**
+	 * @see org.apache.wicket.pageStore.IPageStore#prepareForSerialization(java.lang. String,
+	 *      java.io.Serializable)
+	 */
+	@Override
+	public Serializable prepareForSerialization(String sessionId, Serializable page)
+	{
+		return pageStore.prepareForSerialization(sessionId, page);
+	}
+
+	/**
+	 * @see org.apache.wicket.pageStore.IPageStore#restoreAfterSerialization(java.io. Serializable)
+	 */
+	@Override
+	public Object restoreAfterSerialization(Serializable serializable)
+	{
+		return pageStore.restoreAfterSerialization(serializable);
+	}
+
+	/**
+	 * @see org.apache.wicket.pageStore.IPageStore#convertToPage(java.lang.Object)
+	 */
+	@Override
+	public IManageablePage convertToPage(Object page)
+	{
+		return pageStore.convertToPage(page);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/0e975d72/wicket-core/src/test/java/org/apache/wicket/pageStore/AsyncPageStoreTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/pageStore/AsyncPageStoreTest.java b/wicket-core/src/test/java/org/apache/wicket/pageStore/AsyncPageStoreTest.java
deleted file mode 100644
index 9849471..0000000
--- a/wicket-core/src/test/java/org/apache/wicket/pageStore/AsyncPageStoreTest.java
+++ /dev/null
@@ -1,497 +0,0 @@
-package org.apache.wicket.pageStore;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutput;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.commons.lang3.RandomUtils;
-import org.apache.wicket.page.IManageablePage;
-import org.apache.wicket.serialize.ISerializer;
-import org.apache.wicket.serialize.java.DeflatedJavaSerializer;
-import org.apache.wicket.util.file.File;
-import org.apache.wicket.util.lang.Bytes;
-import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Stopwatch;
-
-/**
- * AsyncPageStoreTest
- * 
- * @author manuelbarzi
- *
- */
-public class AsyncPageStoreTest
-{
-
-	/** Log for reporting. */
-	private static final Logger log = LoggerFactory.getLogger(AsyncPageStoreTest.class);
-
-	@SuppressWarnings("serial")
-	private static class DummyPage implements IManageablePage
-	{
-
-		private int pageId;
-		private long writeMillis;
-		private long readMillis;
-		private String sessionId;
-
-		private DummyPage(int pageId, long writeMillis, long readMillis, String sessionId)
-		{
-			this.pageId = pageId;
-			this.writeMillis = writeMillis;
-			this.readMillis = readMillis;
-			this.sessionId = sessionId;
-		}
-
-		@Override
-		public boolean isPageStateless()
-		{
-			return false;
-		}
-
-		@Override
-		public int getPageId()
-		{
-			return pageId;
-		}
-
-		@Override
-		public void detach()
-		{
-		}
-
-		@Override
-		public boolean setFreezePageId(boolean freeze)
-		{
-			return false;
-		}
-
-		/**
-		 * @param s
-		 * @throws IOException
-		 */
-		private void writeObject(java.io.ObjectOutputStream s) throws IOException
-		{
-			log.debug("serializing page {} for {}ms (session {})", getPageId(), writeMillis,
-				sessionId);
-			try
-			{
-				Thread.sleep(writeMillis);
-			}
-			catch (InterruptedException e)
-			{
-				throw new RuntimeException(e);
-			}
-
-			s.writeInt(pageId);
-			s.writeLong(writeMillis);
-			s.writeLong(readMillis);
-			s.writeObject(sessionId);
-		}
-
-		private void readObject(java.io.ObjectInputStream s)
-			throws IOException, ClassNotFoundException
-		{
-			log.debug("deserializing page {} for {}ms (session {})", getPageId(), writeMillis,
-				sessionId);
-			try
-			{
-				Thread.sleep(readMillis);
-			}
-			catch (InterruptedException e)
-			{
-				throw new RuntimeException(e);
-			}
-
-			pageId = s.readInt();
-			writeMillis = s.readLong();
-			readMillis = s.readLong();
-			sessionId = (String)s.readObject();
-		}
-
-		public String toString()
-		{
-			return "DummyPage[pageId = " + pageId + ", writeMillis = " + writeMillis +
-				", readMillis = " + readMillis + ", sessionId = " + sessionId + ", hashCode = " +
-				hashCode() + "]";
-		}
-	}
-
-	/**
-	 * Store works fully async when number of pages handled never exceeds the async-storage
-	 * capacity.
-	 * 
-	 * @throws InterruptedException
-	 */
-	@Test
-	public void storeBehavesAsyncWhenNotExceedingStoreCapacity() throws InterruptedException
-	{
-		int sessions = 2;
-		int pages = 5;
-		long writeMillis = 2000;
-		long readMillis = 1500;
-		int asyncPageStoreCapacity = pages * sessions;
-
-		List<Metrics> results = runTest(sessions, pages, writeMillis, readMillis,
-			asyncPageStoreCapacity);
-
-		for (Metrics metrics : results)
-			System.out.println(metrics);
-
-		for (Metrics metrics : results)
-		{
-			assertEquals(metrics.storedPage, metrics.restoredPage);
-			assertTrue(metrics.storingMillis < writeMillis);
-			assertTrue(metrics.restoringMillis < readMillis);
-		}
-	}
-
-	/**
-	 * Store behaves sync from when number of pages handled exceeds the given async-storage
-	 * capacity. It works async until the number of pages reaches the limit (capacity).
-	 * 
-	 * @throws InterruptedException
-	 */
-	@Test
-	public void storeBehavesSyncFromWhenExceedingStoreCapacity() throws InterruptedException
-	{
-		int sessions = 2;
-		int pages = 5;
-		long writeMillis = 2000;
-		long readMillis = 1500;
-		int asyncPageStoreCapacity = pages; // only up to the first round of
-											// pages
-
-		List<Metrics> results = runTest(sessions, pages, writeMillis, readMillis,
-			asyncPageStoreCapacity);
-
-		for (Metrics metrics : results)
-			System.out.println(metrics);
-
-		int sync = 0;
-
-		for (int i = 0; i < results.size(); i++)
-		{
-			Metrics metrics = results.get(i);
-
-			assertEquals(metrics.storedPage.sessionId, metrics.restoredPage.sessionId);
-			assertEquals(metrics.storedPage.getPageId(), metrics.restoredPage.getPageId());
-
-			if (!metrics.storedPage.equals(metrics.restoredPage))
-			{
-				assertTrue(metrics.storingMillis >= metrics.storedPage.writeMillis);
-				sync++;
-			}
-		}
-
-		assertTrue(sync > 0);
-	}
-
-	// test run
-
-	private class Metrics
-	{
-		private DummyPage storedPage;
-		private long storingMillis;
-		private DummyPage restoredPage;
-		private long restoringMillis;
-
-		public String toString()
-		{
-			return "Metrics[storedPage = " + storedPage + ", storingMillis = " + storingMillis +
-				", restoredPage = " + restoredPage + ", restoringMillis = " + restoringMillis + "]";
-		}
-	}
-
-	private List<Metrics> runTest(int sessions, int pages, long writeMillis, long readMillis,
-		int asyncPageStoreCapacity) throws InterruptedException
-	{
-
-		List<Metrics> results = new ArrayList<>();
-
-		final CountDownLatch lock = new CountDownLatch(pages * sessions);
-
-		ISerializer serializer = new DeflatedJavaSerializer("applicationKey");
-		// ISerializer serializer = new DummySerializer();
-		IDataStore dataStore = new DiskDataStore("applicationName", new File("./target"),
-			Bytes.bytes(10000l));
-		IPageStore pageStore = new DefaultPageStore(serializer, dataStore, 0)
-		{
-			// IPageStore pageStore = new DummyPageStore(new
-			// File("target/store")) {
-
-			@Override
-			public void storePage(String sessionId, IManageablePage page)
-			{
-
-				super.storePage(sessionId, page);
-
-				lock.countDown();
-			}
-		};
-
-		IPageStore asyncPageStore = new AsyncPageStore(pageStore, asyncPageStoreCapacity);
-
-		Stopwatch stopwatch = Stopwatch.createUnstarted();
-
-		for (int pageId = 1; pageId <= pages; pageId++)
-		{
-			for (int sessionId = 1; sessionId <= sessions; sessionId++)
-			{
-				String session = String.valueOf(sessionId);
-				Metrics metrics = new Metrics();
-
-				stopwatch.reset();
-				DummyPage page = new DummyPage(pageId, around(writeMillis), around(readMillis),
-					session);
-				stopwatch.start();
-				asyncPageStore.storePage(session, page);
-				metrics.storedPage = page;
-				metrics.storingMillis = stopwatch.elapsed(TimeUnit.MILLISECONDS);
-
-				stopwatch.reset();
-				stopwatch.start();
-				metrics.restoredPage = DummyPage.class
-					.cast(asyncPageStore.getPage(session, pageId));
-				metrics.restoringMillis = stopwatch.elapsed(TimeUnit.MILLISECONDS);
-
-				results.add(metrics);
-			}
-		}
-
-		lock.await(pages * sessions * (writeMillis + readMillis), TimeUnit.MILLISECONDS);
-
-		return results;
-	}
-
-	private long around(long target)
-	{
-		return RandomUtils.nextLong((long)(target * .9), (long)(target * 1.1));
-	}
-
-	// other aux dummy impls for testing
-
-	private class DummySerializer implements ISerializer
-	{
-
-		@Override
-		public byte[] serialize(Object obj)
-		{
-			ByteArrayOutputStream bos = null;
-			ObjectOutput out = null;
-			try
-			{
-				bos = new ByteArrayOutputStream();
-				out = new ObjectOutputStream(bos);
-				out.writeObject(obj);
-				return bos.toByteArray();
-			}
-			catch (FileNotFoundException e)
-			{
-				throw new RuntimeException(e);
-			}
-			catch (IOException e)
-			{
-				throw new RuntimeException(e);
-			}
-			finally
-			{
-				try
-				{
-					if (bos != null)
-						bos.close();
-					if (out != null)
-						out.close();
-				}
-				catch (IOException e)
-				{
-					throw new RuntimeException(e);
-				}
-			}
-		}
-
-		@Override
-		public Object deserialize(byte[] bytes)
-		{
-			ByteArrayInputStream bis = null;
-			ObjectInput in = null;
-			try
-			{
-				bis = new ByteArrayInputStream(bytes);
-				in = new ObjectInputStream(bis);
-				return in.readObject();
-			}
-			catch (IOException e)
-			{
-				throw new RuntimeException(e);
-			}
-			catch (ClassNotFoundException e)
-			{
-				throw new RuntimeException(e);
-			}
-			finally
-			{
-				try
-				{
-					if (bis != null)
-						bis.close();
-					if (in != null)
-						in.close();
-				}
-				catch (IOException e)
-				{
-					throw new RuntimeException(e);
-				}
-			}
-		}
-
-	}
-
-	private class DummyPageStore implements IPageStore
-	{
-
-		private File folder;
-
-		private DummyPageStore(File folder)
-		{
-			folder.mkdirs();
-			this.folder = folder;
-		}
-
-		private File getPageFile(String sessionId, int pageId)
-		{
-			return new File(folder.getAbsolutePath() + "/" + sessionId + "-" + pageId + ".page");
-		}
-
-		private void toFile(Object obj, File file)
-		{
-			FileOutputStream fos = null;
-			ObjectOutput oo = null;
-			try
-			{
-				fos = new FileOutputStream(file);
-				oo = new ObjectOutputStream(fos);
-				oo.writeObject(obj);
-			}
-			catch (FileNotFoundException e)
-			{
-				throw new RuntimeException(e);
-			}
-			catch (IOException e)
-			{
-				throw new RuntimeException(e);
-			}
-			finally
-			{
-				try
-				{
-					if (fos != null)
-						fos.close();
-					if (oo != null)
-						oo.close();
-				}
-				catch (IOException e)
-				{
-					throw new RuntimeException(e);
-				}
-			}
-		}
-
-		private Object fromFile(File file)
-		{
-			FileInputStream fis = null;
-			ObjectInput oi = null;
-			try
-			{
-				fis = new FileInputStream(file);
-				oi = new ObjectInputStream(fis);
-				return oi.readObject();
-			}
-			catch (IOException e)
-			{
-				throw new RuntimeException(e);
-			}
-			catch (ClassNotFoundException e)
-			{
-				throw new RuntimeException(e);
-			}
-			finally
-			{
-				try
-				{
-					if (fis != null)
-						fis.close();
-					if (oi != null)
-						oi.close();
-				}
-				catch (IOException e)
-				{
-					throw new RuntimeException(e);
-				}
-			}
-		}
-
-		@Override
-		public void destroy()
-		{
-		}
-
-		@Override
-		public IManageablePage getPage(String sessionId, int pageId)
-		{
-			return (IManageablePage)fromFile(getPageFile(sessionId, pageId));
-		}
-
-		@Override
-		public void removePage(String sessionId, int pageId)
-		{
-		}
-
-		@Override
-		public void storePage(String sessionId, IManageablePage page)
-		{
-			toFile(page, getPageFile(sessionId, page.getPageId()));
-		}
-
-		@Override
-		public void unbind(String sessionId)
-		{
-		}
-
-		@Override
-		public Serializable prepareForSerialization(String sessionId, Serializable page)
-		{
-			return null;
-		}
-
-		@Override
-		public Object restoreAfterSerialization(Serializable serializable)
-		{
-			return null;
-		}
-
-		@Override
-		public IManageablePage convertToPage(Object page)
-		{
-			return null;
-		}
-	}
-
-}

http://git-wip-us.apache.org/repos/asf/wicket/blob/0e975d72/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java b/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java
new file mode 100644
index 0000000..53da7d6
--- /dev/null
+++ b/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java
@@ -0,0 +1,498 @@
+package org.apache.wicket.pageStore;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.lang3.RandomUtils;
+import org.apache.wicket.page.IManageablePage;
+import org.apache.wicket.serialize.ISerializer;
+import org.apache.wicket.serialize.java.DeflatedJavaSerializer;
+import org.apache.wicket.util.file.File;
+import org.apache.wicket.util.lang.Bytes;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Stopwatch;
+
+/**
+ * AsynchronousPageStoreTest
+ * 
+ * @author manuelbarzi
+ *
+ */
+public class AsynchronousPageStoreTest
+{
+
+	/** Log for reporting. */
+	private static final Logger log = LoggerFactory.getLogger(AsynchronousPageStoreTest.class);
+
+	@SuppressWarnings("serial")
+	private static class DummyPage implements IManageablePage
+	{
+
+		private int pageId;
+		private long writeMillis;
+		private long readMillis;
+		private String sessionId;
+
+		private DummyPage(int pageId, long writeMillis, long readMillis, String sessionId)
+		{
+			this.pageId = pageId;
+			this.writeMillis = writeMillis;
+			this.readMillis = readMillis;
+			this.sessionId = sessionId;
+		}
+
+		@Override
+		public boolean isPageStateless()
+		{
+			return false;
+		}
+
+		@Override
+		public int getPageId()
+		{
+			return pageId;
+		}
+
+		@Override
+		public void detach()
+		{
+		}
+
+		@Override
+		public boolean setFreezePageId(boolean freeze)
+		{
+			return false;
+		}
+
+		/**
+		 * @param s
+		 * @throws IOException
+		 */
+		private void writeObject(java.io.ObjectOutputStream s) throws IOException
+		{
+			log.debug("serializing page {} for {}ms (session {})", getPageId(), writeMillis,
+				sessionId);
+			try
+			{
+				Thread.sleep(writeMillis);
+			}
+			catch (InterruptedException e)
+			{
+				throw new RuntimeException(e);
+			}
+
+			s.writeInt(pageId);
+			s.writeLong(writeMillis);
+			s.writeLong(readMillis);
+			s.writeObject(sessionId);
+		}
+
+		private void readObject(java.io.ObjectInputStream s)
+			throws IOException, ClassNotFoundException
+		{
+			log.debug("deserializing page {} for {}ms (session {})", getPageId(), writeMillis,
+				sessionId);
+			try
+			{
+				Thread.sleep(readMillis);
+			}
+			catch (InterruptedException e)
+			{
+				throw new RuntimeException(e);
+			}
+
+			pageId = s.readInt();
+			writeMillis = s.readLong();
+			readMillis = s.readLong();
+			sessionId = (String)s.readObject();
+		}
+
+		public String toString()
+		{
+			return "DummyPage[pageId = " + pageId + ", writeMillis = " + writeMillis +
+				", readMillis = " + readMillis + ", sessionId = " + sessionId + ", hashCode = " +
+				hashCode() + "]";
+		}
+	}
+
+	/**
+	 * Store works fully asynchronous when number of pages handled never exceeds the
+	 * asynchronous-storage capacity.
+	 * 
+	 * @throws InterruptedException
+	 */
+	@Test
+	public void storeBehavesAsyncWhenNotExceedingStoreCapacity() throws InterruptedException
+	{
+		int sessions = 2;
+		int pages = 5;
+		long writeMillis = 2000;
+		long readMillis = 1500;
+		int asyncPageStoreCapacity = pages * sessions;
+
+		List<Metrics> results = runTest(sessions, pages, writeMillis, readMillis,
+			asyncPageStoreCapacity);
+
+		for (Metrics metrics : results)
+			System.out.println(metrics);
+
+		for (Metrics metrics : results)
+		{
+			assertEquals(metrics.storedPage, metrics.restoredPage);
+			assertTrue(metrics.storingMillis < writeMillis);
+			assertTrue(metrics.restoringMillis < readMillis);
+		}
+	}
+
+	/**
+	 * Store behaves synchronous from when number of pages handled exceeds the given
+	 * asynchronous-storage capacity. It works asynchronous until the number of pages reaches the
+	 * limit (capacity).
+	 * 
+	 * @throws InterruptedException
+	 */
+	@Test
+	public void storeBehavesSyncFromWhenExceedingStoreCapacity() throws InterruptedException
+	{
+		int sessions = 2;
+		int pages = 5;
+		long writeMillis = 2000;
+		long readMillis = 1500;
+		int asyncPageStoreCapacity = pages; // only up to the first round of
+											// pages
+
+		List<Metrics> results = runTest(sessions, pages, writeMillis, readMillis,
+			asyncPageStoreCapacity);
+
+		for (Metrics metrics : results)
+			System.out.println(metrics);
+
+		int sync = 0;
+
+		for (int i = 0; i < results.size(); i++)
+		{
+			Metrics metrics = results.get(i);
+
+			assertEquals(metrics.storedPage.sessionId, metrics.restoredPage.sessionId);
+			assertEquals(metrics.storedPage.getPageId(), metrics.restoredPage.getPageId());
+
+			if (!metrics.storedPage.equals(metrics.restoredPage))
+			{
+				assertTrue(metrics.storingMillis >= metrics.storedPage.writeMillis);
+				sync++;
+			}
+		}
+
+		assertTrue(sync > 0);
+	}
+
+	// test run
+
+	private class Metrics
+	{
+		private DummyPage storedPage;
+		private long storingMillis;
+		private DummyPage restoredPage;
+		private long restoringMillis;
+
+		public String toString()
+		{
+			return "Metrics[storedPage = " + storedPage + ", storingMillis = " + storingMillis +
+				", restoredPage = " + restoredPage + ", restoringMillis = " + restoringMillis + "]";
+		}
+	}
+
+	private List<Metrics> runTest(int sessions, int pages, long writeMillis, long readMillis,
+		int asyncPageStoreCapacity) throws InterruptedException
+	{
+
+		List<Metrics> results = new ArrayList<>();
+
+		final CountDownLatch lock = new CountDownLatch(pages * sessions);
+
+		ISerializer serializer = new DeflatedJavaSerializer("applicationKey");
+		// ISerializer serializer = new DummySerializer();
+		IDataStore dataStore = new DiskDataStore("applicationName", new File("./target"),
+			Bytes.bytes(10000l));
+		IPageStore pageStore = new DefaultPageStore(serializer, dataStore, 0)
+		{
+			// IPageStore pageStore = new DummyPageStore(new
+			// File("target/store")) {
+
+			@Override
+			public void storePage(String sessionId, IManageablePage page)
+			{
+
+				super.storePage(sessionId, page);
+
+				lock.countDown();
+			}
+		};
+
+		IPageStore asyncPageStore = new AsynchronousPageStore(pageStore, asyncPageStoreCapacity);
+
+		Stopwatch stopwatch = Stopwatch.createUnstarted();
+
+		for (int pageId = 1; pageId <= pages; pageId++)
+		{
+			for (int sessionId = 1; sessionId <= sessions; sessionId++)
+			{
+				String session = String.valueOf(sessionId);
+				Metrics metrics = new Metrics();
+
+				stopwatch.reset();
+				DummyPage page = new DummyPage(pageId, around(writeMillis), around(readMillis),
+					session);
+				stopwatch.start();
+				asyncPageStore.storePage(session, page);
+				metrics.storedPage = page;
+				metrics.storingMillis = stopwatch.elapsed(TimeUnit.MILLISECONDS);
+
+				stopwatch.reset();
+				stopwatch.start();
+				metrics.restoredPage = DummyPage.class
+					.cast(asyncPageStore.getPage(session, pageId));
+				metrics.restoringMillis = stopwatch.elapsed(TimeUnit.MILLISECONDS);
+
+				results.add(metrics);
+			}
+		}
+
+		lock.await(pages * sessions * (writeMillis + readMillis), TimeUnit.MILLISECONDS);
+
+		return results;
+	}
+
+	private long around(long target)
+	{
+		return RandomUtils.nextLong((long)(target * .9), (long)(target * 1.1));
+	}
+
+	// other aux dummy impls for testing
+
+	private class DummySerializer implements ISerializer
+	{
+
+		@Override
+		public byte[] serialize(Object obj)
+		{
+			ByteArrayOutputStream bos = null;
+			ObjectOutput out = null;
+			try
+			{
+				bos = new ByteArrayOutputStream();
+				out = new ObjectOutputStream(bos);
+				out.writeObject(obj);
+				return bos.toByteArray();
+			}
+			catch (FileNotFoundException e)
+			{
+				throw new RuntimeException(e);
+			}
+			catch (IOException e)
+			{
+				throw new RuntimeException(e);
+			}
+			finally
+			{
+				try
+				{
+					if (bos != null)
+						bos.close();
+					if (out != null)
+						out.close();
+				}
+				catch (IOException e)
+				{
+					throw new RuntimeException(e);
+				}
+			}
+		}
+
+		@Override
+		public Object deserialize(byte[] bytes)
+		{
+			ByteArrayInputStream bis = null;
+			ObjectInput in = null;
+			try
+			{
+				bis = new ByteArrayInputStream(bytes);
+				in = new ObjectInputStream(bis);
+				return in.readObject();
+			}
+			catch (IOException e)
+			{
+				throw new RuntimeException(e);
+			}
+			catch (ClassNotFoundException e)
+			{
+				throw new RuntimeException(e);
+			}
+			finally
+			{
+				try
+				{
+					if (bis != null)
+						bis.close();
+					if (in != null)
+						in.close();
+				}
+				catch (IOException e)
+				{
+					throw new RuntimeException(e);
+				}
+			}
+		}
+
+	}
+
+	private class DummyPageStore implements IPageStore
+	{
+
+		private File folder;
+
+		private DummyPageStore(File folder)
+		{
+			folder.mkdirs();
+			this.folder = folder;
+		}
+
+		private File getPageFile(String sessionId, int pageId)
+		{
+			return new File(folder.getAbsolutePath() + "/" + sessionId + "-" + pageId + ".page");
+		}
+
+		private void toFile(Object obj, File file)
+		{
+			FileOutputStream fos = null;
+			ObjectOutput oo = null;
+			try
+			{
+				fos = new FileOutputStream(file);
+				oo = new ObjectOutputStream(fos);
+				oo.writeObject(obj);
+			}
+			catch (FileNotFoundException e)
+			{
+				throw new RuntimeException(e);
+			}
+			catch (IOException e)
+			{
+				throw new RuntimeException(e);
+			}
+			finally
+			{
+				try
+				{
+					if (fos != null)
+						fos.close();
+					if (oo != null)
+						oo.close();
+				}
+				catch (IOException e)
+				{
+					throw new RuntimeException(e);
+				}
+			}
+		}
+
+		private Object fromFile(File file)
+		{
+			FileInputStream fis = null;
+			ObjectInput oi = null;
+			try
+			{
+				fis = new FileInputStream(file);
+				oi = new ObjectInputStream(fis);
+				return oi.readObject();
+			}
+			catch (IOException e)
+			{
+				throw new RuntimeException(e);
+			}
+			catch (ClassNotFoundException e)
+			{
+				throw new RuntimeException(e);
+			}
+			finally
+			{
+				try
+				{
+					if (fis != null)
+						fis.close();
+					if (oi != null)
+						oi.close();
+				}
+				catch (IOException e)
+				{
+					throw new RuntimeException(e);
+				}
+			}
+		}
+
+		@Override
+		public void destroy()
+		{
+		}
+
+		@Override
+		public IManageablePage getPage(String sessionId, int pageId)
+		{
+			return (IManageablePage)fromFile(getPageFile(sessionId, pageId));
+		}
+
+		@Override
+		public void removePage(String sessionId, int pageId)
+		{
+		}
+
+		@Override
+		public void storePage(String sessionId, IManageablePage page)
+		{
+			toFile(page, getPageFile(sessionId, page.getPageId()));
+		}
+
+		@Override
+		public void unbind(String sessionId)
+		{
+		}
+
+		@Override
+		public Serializable prepareForSerialization(String sessionId, Serializable page)
+		{
+			return null;
+		}
+
+		@Override
+		public Object restoreAfterSerialization(Serializable serializable)
+		{
+			return null;
+		}
+
+		@Override
+		public IManageablePage convertToPage(Object page)
+		{
+			return null;
+		}
+	}
+
+}


[07/10] wicket git commit: subordinate page-store async-check in/to data-store async-check

Posted by mg...@apache.org.
subordinate page-store async-check in/to data-store async-check


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

Branch: refs/heads/master
Commit: acf7efbaeac0d368b1fdfcb08de598868a95dc81
Parents: 0ebf51e
Author: Manuel Barzi <ma...@Manuels-MacBook-Pro.local>
Authored: Thu Apr 6 19:39:00 2017 +0200
Committer: Manuel Barzi <ma...@Manuels-MacBook-Pro.local>
Committed: Thu Apr 6 19:39:00 2017 +0200

----------------------------------------------------------------------
 .../wicket/DefaultPageManagerProvider.java       | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/acf7efba/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 14387a4..d7b0b45 100644
--- a/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
+++ b/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
@@ -58,20 +58,23 @@ public class DefaultPageManagerProvider implements IPageManagerProvider
 
 		StoreSettings storeSettings = getStoreSettings();
 
+		IPageStore pageStore;
+
 		if (dataStore.canBeAsynchronous())
 		{
 			int capacity = storeSettings.getAsynchronousQueueCapacity();
 			dataStore = new AsynchronousDataStore(dataStore, capacity);
-		}
 
-		IPageStore pageStore = newPageStore(dataStore);
-		
-		if (pageStore.canBeAsynchronous())
-		{
-			int capacity = storeSettings.getAsynchronousQueueCapacity();
-			pageStore = new AsynchronousPageStore(pageStore, capacity);
+			pageStore = newPageStore(dataStore);
+
+			if (pageStore.canBeAsynchronous())
+			{
+				pageStore = new AsynchronousPageStore(pageStore, capacity);
+			}
 		}
-		
+		else
+			pageStore = newPageStore(dataStore);
+
 		return new PageStoreManager(application.getName(), pageStore, pageManagerContext);
 
 	}


[04/10] wicket git commit: provide can-be flag for asynchronous wrapping to page store and logic into default page manager provider

Posted by mg...@apache.org.
provide can-be flag for asynchronous wrapping to page store and logic into default page manager provider


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

Branch: refs/heads/master
Commit: accf1873197e759ec08db3e95e22fe2193f343ee
Parents: 6886c2b
Author: Manuel Barzi <ma...@Manuels-MacBook-Pro.local>
Authored: Thu Mar 16 13:27:16 2017 +0100
Committer: Manuel Barzi <ma...@Manuels-MacBook-Pro.local>
Committed: Thu Mar 16 13:27:16 2017 +0100

----------------------------------------------------------------------
 .../java/org/apache/wicket/DefaultPageManagerProvider.java   | 8 ++++++++
 .../org/apache/wicket/pageStore/AsynchronousPageStore.java   | 6 ++++++
 .../java/org/apache/wicket/pageStore/DefaultPageStore.java   | 6 ++++++
 .../main/java/org/apache/wicket/pageStore/IPageStore.java    | 5 +++++
 .../org/apache/wicket/pageStore/PerSessionPageStore.java     | 7 +++++++
 .../apache/wicket/pageStore/AsynchronousPageStoreTest.java   | 6 ++++++
 6 files changed, 38 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/accf1873/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 c997648..14387a4 100644
--- a/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
+++ b/wicket-core/src/main/java/org/apache/wicket/DefaultPageManagerProvider.java
@@ -22,6 +22,7 @@ import org.apache.wicket.page.IPageManager;
 import org.apache.wicket.page.IPageManagerContext;
 import org.apache.wicket.page.PageStoreManager;
 import org.apache.wicket.pageStore.AsynchronousDataStore;
+import org.apache.wicket.pageStore.AsynchronousPageStore;
 import org.apache.wicket.pageStore.DefaultPageStore;
 import org.apache.wicket.pageStore.DiskDataStore;
 import org.apache.wicket.pageStore.IDataStore;
@@ -64,6 +65,13 @@ public class DefaultPageManagerProvider implements IPageManagerProvider
 		}
 
 		IPageStore pageStore = newPageStore(dataStore);
+		
+		if (pageStore.canBeAsynchronous())
+		{
+			int capacity = storeSettings.getAsynchronousQueueCapacity();
+			pageStore = new AsynchronousPageStore(pageStore, capacity);
+		}
+		
 		return new PageStoreManager(application.getName(), pageStore, pageManagerContext);
 
 	}

http://git-wip-us.apache.org/repos/asf/wicket/blob/accf1873/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousPageStore.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousPageStore.java
index 087257c..3c77df6 100644
--- a/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousPageStore.java
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousPageStore.java
@@ -355,4 +355,10 @@ public class AsynchronousPageStore implements IPageStore
 		return pageStore.convertToPage(page);
 	}
 
+	@Override
+	public boolean canBeAsynchronous()
+	{
+		return false;
+	}
+
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/accf1873/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 e574f37..f324b85 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
@@ -460,4 +460,10 @@ public class DefaultPageStore extends AbstractCachingPageStore<DefaultPageStore.
 			cache.clear();
 		}
 	}
+
+	@Override
+	public boolean canBeAsynchronous()
+	{
+		return true;
+	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/accf1873/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 470536a..ed1b9d3 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
@@ -103,4 +103,9 @@ public interface IPageStore
 	 * @return page
 	 */
 	IManageablePage convertToPage(Object page);
+	
+	/**
+	 * @return whether the implementation can be wrapped in {@link AsynchronousPageStore}
+	 */
+	boolean canBeAsynchronous();
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/accf1873/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
index 912171c..abef0c9 100644
--- a/wicket-core/src/main/java/org/apache/wicket/pageStore/PerSessionPageStore.java
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/PerSessionPageStore.java
@@ -323,4 +323,11 @@ public class PerSessionPageStore extends AbstractCachingPageStore<IManageablePag
 			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/accf1873/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java b/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java
index 53da7d6..2a0acf9 100644
--- a/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java
@@ -493,6 +493,12 @@ public class AsynchronousPageStoreTest
 		{
 			return null;
 		}
+
+		@Override
+		public boolean canBeAsynchronous()
+		{
+			return true;
+		}
 	}
 
 }


[08/10] wicket git commit: Merge remote-tracking branch 'barzi/master' into pr-212-master

Posted by mg...@apache.org.
Merge remote-tracking branch 'barzi/master' into pr-212-master


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

Branch: refs/heads/master
Commit: a4e28b8a028fc984e2b384596d2ae94e1343a2e7
Parents: c45af37 acf7efb
Author: Martin Tzvetanov Grigorov <mg...@apache.org>
Authored: Wed Apr 12 22:53:30 2017 +0200
Committer: Martin Tzvetanov Grigorov <mg...@apache.org>
Committed: Wed Apr 12 22:53:30 2017 +0200

----------------------------------------------------------------------
 pom.xml                                         |  10 +
 wicket-core/pom.xml                             |  10 +
 .../wicket/DefaultPageManagerProvider.java      |  13 +-
 .../wicket/pageStore/AsynchronousPageStore.java | 364 ++++++++++++
 .../wicket/pageStore/DefaultPageStore.java      |   6 +
 .../org/apache/wicket/pageStore/IPageStore.java |   5 +
 .../wicket/pageStore/PerSessionPageStore.java   |   7 +
 .../pageStore/AsynchronousPageStoreTest.java    | 582 +++++++++++++++++++
 8 files changed, 996 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/a4e28b8a/pom.xml
----------------------------------------------------------------------


[05/10] wicket git commit: add store page retrieval tests on close and distant requests back

Posted by mg...@apache.org.
add store page retrieval tests on close and distant requests back


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

Branch: refs/heads/master
Commit: 2bae2cbae378d9732ca3549ab77019d08a134302
Parents: accf187
Author: Manuel Barzi <ma...@Manuels-MacBook-Pro.local>
Authored: Sun Apr 2 15:07:59 2017 +0200
Committer: Manuel Barzi <ma...@Manuels-MacBook-Pro.local>
Committed: Sun Apr 2 15:07:59 2017 +0200

----------------------------------------------------------------------
 .../pageStore/AsynchronousPageStoreTest.java    | 113 ++++++++++++++++---
 1 file changed, 95 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/2bae2cba/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java b/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java
index 2a0acf9..d437d30 100644
--- a/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java
@@ -2,6 +2,10 @@ package org.apache.wicket.pageStore;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -21,6 +25,10 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.commons.lang3.RandomUtils;
 import org.apache.wicket.page.IManageablePage;
+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.serialize.ISerializer;
 import org.apache.wicket.serialize.java.DeflatedJavaSerializer;
 import org.apache.wicket.util.file.File;
@@ -128,13 +136,81 @@ public class AsynchronousPageStoreTest
 
 		public String toString()
 		{
-			return "DummyPage[pageId = " + pageId + ", writeMillis = " + writeMillis +
-				", readMillis = " + readMillis + ", sessionId = " + sessionId + ", hashCode = " +
-				hashCode() + "]";
+			return "DummyPage[pageId = " + pageId + ", writeMillis = " + writeMillis
+				+ ", readMillis = " + readMillis + ", sessionId = " + sessionId + ", hashCode = "
+				+ hashCode() + "]";
 		}
 	}
 
 	/**
+	 * Store returns the same page instance from queue when there is a close request for it back
+	 * again.
+	 * 
+	 * @throws InterruptedException
+	 */
+	@Test
+	public void storeReturnsSameInstanceOnClosePageRequest() throws InterruptedException
+	{
+
+		ISerializer serializer = new DeflatedJavaSerializer("applicationKey");
+		// ISerializer serializer = new DummySerializer();
+
+		IDataStore dataStore = new DiskDataStore("applicationName", new File("./target"),
+			Bytes.bytes(10000l));
+
+		// IPageStore pageStore = new DummyPageStore(new File("target/store"));
+		IPageStore pageStore = spy(new DefaultPageStore(serializer, dataStore, 0));
+
+		IPageStore asyncPageStore = new AsynchronousPageStore(pageStore, 100);
+
+		int pageId = 0;
+		String sessionId = "sessionId";
+
+		DummyPage page = new DummyPage(pageId, 1000, 1000, sessionId);
+		asyncPageStore.storePage(sessionId, page);
+
+		Thread.sleep(500);
+
+		asyncPageStore.getPage(sessionId, pageId);
+
+		verify(pageStore, never()).getPage(sessionId, pageId);
+	}
+
+	/**
+	 * Store returns the restored page instance from wrapped store when there is a distant request
+	 * for it back again.
+	 * 
+	 * @throws InterruptedException
+	 */
+	@Test
+	public void storeReturnsRestoredInstanceOnDistantPageRequest() throws InterruptedException
+	{
+
+		ISerializer serializer = new DeflatedJavaSerializer("applicationKey");
+		// ISerializer serializer = new DummySerializer();
+
+		IDataStore dataStore = new DiskDataStore("applicationName", new File("./target"),
+			Bytes.bytes(10000l));
+
+		// IPageStore pageStore = new DummyPageStore(new File("target/store"));
+		IPageStore pageStore = spy(new DefaultPageStore(serializer, dataStore, 0));
+
+		IPageStore asyncPageStore = new AsynchronousPageStore(pageStore, 100);
+
+		int pageId = 0;
+		String sessionId = "sessionId";
+
+		DummyPage page = new DummyPage(pageId, 1000, 1000, sessionId);
+		asyncPageStore.storePage(sessionId, page);
+
+		Thread.sleep(1500);
+
+		asyncPageStore.getPage(sessionId, pageId);
+
+		verify(pageStore, times(1)).getPage(sessionId, pageId);
+	}
+
+	/**
 	 * Store works fully asynchronous when number of pages handled never exceeds the
 	 * asynchronous-storage capacity.
 	 * 
@@ -164,9 +240,8 @@ public class AsynchronousPageStoreTest
 	}
 
 	/**
-	 * Store behaves synchronous from when number of pages handled exceeds the given
-	 * asynchronous-storage capacity. It works asynchronous until the number of pages reaches the
-	 * limit (capacity).
+	 * Store behaves sync from when number of pages handled exceeds the given asynchronous-storage
+	 * capacity. It works asynchronous until the number of pages reaches the limit (capacity).
 	 * 
 	 * @throws InterruptedException
 	 */
@@ -216,8 +291,9 @@ public class AsynchronousPageStoreTest
 
 		public String toString()
 		{
-			return "Metrics[storedPage = " + storedPage + ", storingMillis = " + storingMillis +
-				", restoredPage = " + restoredPage + ", restoringMillis = " + restoringMillis + "]";
+			return "Metrics[storedPage = " + storedPage + ", storingMillis = " + storingMillis
+				+ ", restoredPage = " + restoredPage + ", restoringMillis = " + restoringMillis
+				+ "]";
 		}
 	}
 
@@ -229,14 +305,15 @@ public class AsynchronousPageStoreTest
 
 		final CountDownLatch lock = new CountDownLatch(pages * sessions);
 
-		ISerializer serializer = new DeflatedJavaSerializer("applicationKey");
 		// ISerializer serializer = new DummySerializer();
+		ISerializer serializer = new DeflatedJavaSerializer("applicationKey");
+
 		IDataStore dataStore = new DiskDataStore("applicationName", new File("./target"),
 			Bytes.bytes(10000l));
+
+		// IPageStore pageStore = new DummyPageStore(new File("target/store")) {
 		IPageStore pageStore = new DefaultPageStore(serializer, dataStore, 0)
 		{
-			// IPageStore pageStore = new DummyPageStore(new
-			// File("target/store")) {
 
 			@Override
 			public void storePage(String sessionId, IManageablePage page)
@@ -254,23 +331,23 @@ public class AsynchronousPageStoreTest
 
 		for (int pageId = 1; pageId <= pages; pageId++)
 		{
-			for (int sessionId = 1; sessionId <= sessions; sessionId++)
+			for (int i = 1; i <= sessions; i++)
 			{
-				String session = String.valueOf(sessionId);
+				String sessionId = String.valueOf(i);
 				Metrics metrics = new Metrics();
 
 				stopwatch.reset();
 				DummyPage page = new DummyPage(pageId, around(writeMillis), around(readMillis),
-					session);
+					sessionId);
 				stopwatch.start();
-				asyncPageStore.storePage(session, page);
+				asyncPageStore.storePage(sessionId, page);
 				metrics.storedPage = page;
 				metrics.storingMillis = stopwatch.elapsed(TimeUnit.MILLISECONDS);
 
 				stopwatch.reset();
 				stopwatch.start();
 				metrics.restoredPage = DummyPage.class
-					.cast(asyncPageStore.getPage(session, pageId));
+					.cast(asyncPageStore.getPage(sessionId, pageId));
 				metrics.restoringMillis = stopwatch.elapsed(TimeUnit.MILLISECONDS);
 
 				results.add(metrics);
@@ -497,8 +574,8 @@ public class AsynchronousPageStoreTest
 		@Override
 		public boolean canBeAsynchronous()
 		{
-			return true;
+			return false;
 		}
 	}
 
-}
+}
\ No newline at end of file


[03/10] wicket git commit: Merge branch 'master' of https://github.com/apache/wicket

Posted by mg...@apache.org.
Merge branch 'master' of https://github.com/apache/wicket


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

Branch: refs/heads/master
Commit: 6886c2b229059c36ae347f5e976cd06d6ff47985
Parents: 0e975d7 fb5a2fa
Author: Manuel Barzi <ma...@Manuels-MacBook-Pro.local>
Authored: Thu Mar 16 12:57:01 2017 +0100
Committer: Manuel Barzi <ma...@Manuels-MacBook-Pro.local>
Committed: Thu Mar 16 12:57:01 2017 +0100

----------------------------------------------------------------------
 .../main/resources/archetype-resources/pom.xml  |   6 +-
 pom.xml                                         |  22 ++--
 wicket-core/pom.xml                             |   4 +-
 .../org/apache/wicket/DefaultMapperContext.java |   2 +-
 .../java/org/apache/wicket/ResourceBundles.java |  32 ++++-
 .../main/java/org/apache/wicket/Session.java    |   4 +-
 .../ajax/AbstractDefaultAjaxBehavior.java       |   9 +-
 .../org/apache/wicket/ajax/json/JsonUtils.java  |   6 +-
 .../wicket/ajax/markup/html/AjaxLink.java       |  54 --------
 .../ajax/markup/html/form/AjaxButton.java       |  64 ---------
 .../ajax/markup/html/form/AjaxCheckBox.java     |  28 ----
 .../markup/html/form/AjaxFallbackButton.java    |  14 +-
 .../ajax/markup/html/form/AjaxSubmitLink.java   |  64 ---------
 .../wicket/core/util/lang/WicketObjects.java    |  16 ++-
 .../java/org/apache/wicket/lambda/Lambdas.java  | 132 +------------------
 .../apache/wicket/markup/html/form/Button.java  |  65 +--------
 .../html/form/CheckBoxMultipleChoice.java       |  68 ++++++++--
 .../wicket/markup/html/form/RadioChoice.java    |  22 ++--
 .../apache/wicket/markup/html/link/Link.java    |  29 +---
 .../org/apache/wicket/mock/MockPageManager.java |  12 +-
 .../apache/wicket/page/AbstractPageManager.java |  18 ++-
 .../org/apache/wicket/page/IPageManager.java    |   9 ++
 .../wicket/page/PageAccessSynchronizer.java     |  16 +++
 .../wicket/page/PageManagerDecorator.java       |   5 +
 .../apache/wicket/page/PageStoreManager.java    |  22 ++++
 .../org/apache/wicket/page/RequestAdapter.java  |   9 ++
 .../http/servlet/DispatchedRequestUtils.java    |   2 +-
 .../protocol/http/servlet/ErrorAttributes.java  |  27 ++--
 .../http/servlet/ForwardAttributes.java         |  48 ++++---
 .../java/org/apache/wicket/ajax/HomePage.java   |   5 -
 .../wicket/ajax/form/AjaxFormSubmitTest.java    |  76 +++++++++--
 .../ajax/form/AjaxFormSubmitTestPage.java       |  50 +++++--
 .../form/AjaxFormSubmitTestPage_expected.html   |  14 +-
 ...ketComponentTreeTestPage_ExpectedResult.html |   4 +-
 .../html/form/CheckBoxMultipleChoiceTest.java   |  62 +++++++--
 .../html/form/FormWithMultipleButtonsTest.java  |   5 -
 .../resource/BundlesPage_result_defer.html      |   6 +
 .../request/resource/ResouceBundleTest.java     |  17 +++
 .../devutils/inspector/EnhancedPageView.java    |   7 +-
 .../devutils/inspector/SessionSizeModel.java    |   2 +-
 .../inspector/SessionSizeModelTest.java         |   2 +-
 .../wicket/examples/ajax/builtin/LinksPage.java |  28 ++--
 .../examples/ajax/builtin/WorldClockPage.java   |  14 +-
 .../wicket/examples/authorization/Index.java    |   6 +-
 .../pages/AnnotationsPanelsPage.java            |  24 ++--
 .../examples/captcha/AbstractCaptchaForm.java   |  13 +-
 .../examples/cdi/AutoConversationPage1.java     |  16 ++-
 .../wicket/examples/cdi/ConversationPage1.java  |  20 ++-
 .../wicket/examples/cdi/ConversationPage2.java  |   8 +-
 .../wicket/examples/cdi/InjectionPage.java      |   8 +-
 .../wicket/examples/compref/LinkPage.java       |  18 ++-
 .../examples/compref/NonBookmarkablePage.java   |   6 +-
 .../events/DecoupledAjaxUpdatePage.java         |  10 +-
 .../wicket/examples/forminput/FormInput.java    |  21 +--
 .../apache/wicket/examples/guice/HomePage.java  |   9 +-
 .../apache/wicket/examples/hangman/Lose.java    |  13 +-
 .../org/apache/wicket/examples/hangman/Win.java |  13 +-
 .../wicket/examples/kittenCaptcha/HomePage.java |  31 +++--
 .../apache/wicket/examples/linkomatic/Home.java |  86 ++++++++----
 .../org/apache/wicket/examples/media/Home.java  |   2 +-
 .../wicket/examples/repeater/OIRPage.java       |  16 ++-
 .../examples/repeater/RefreshingPage.java       |  11 +-
 .../wicket/examples/stateless/StatefulPage.java |  17 ++-
 .../template/border/TemplateBorder.java         |  21 +--
 .../template/pageinheritance/TemplatePage.java  |  21 +--
 .../wicket/examples/tree/AdvancedTreePage.java  |  29 +++-
 .../content/CheckedSelectableFolderContent.java |   2 +-
 .../tree/content/EditableFolderContent.java     |   2 +-
 .../content/MultiSelectableFolderContent.java   |   2 +-
 .../tree/content/SelectableFolderContent.java   |   4 +-
 .../wicket/examples/upload/UploadPage.java      |  13 +-
 .../http2/markup/head/NoopPushBuilder.java      |   7 +-
 .../http2/markup/head/Tomcat85PushBuilder.java  |   3 -
 .../html/autocomplete/wicket-autocomplete.js    |   6 +-
 .../ajax/markup/html/modal/ModalWindow.java     |   2 +-
 .../data/table/export/ExportToolbar.java        |  34 +++--
 .../markup/html/repeater/tree/AbstractTree.java |  21 +--
 .../markup/html/repeater/tree/NestedTree.java   |  65 ++++-----
 .../markup/html/repeater/tree/Node.java         |   9 +-
 .../markup/html/repeater/tree/TableTree.java    |  38 +++---
 .../html/repeater/util/TreeModelProvider.java   |   5 +-
 .../InstrumentationObjectSizeOfStrategy.java    |   8 +-
 .../request/mapper/CompoundRequestMapper.java   |   6 +-
 .../mapper/parameter/INamedParameters.java      |   2 +-
 .../mapper/parameter/PageParameters.java        |   2 +
 .../mapper/parameter/PageParametersTest.java    |  35 ++++-
 wicket-user-guide/pom.xml                       |  13 --
 .../src/main/asciidoc/ajax/ajax_3.adoc          |   2 +-
 .../src/main/asciidoc/contributing.adoc         |   4 +-
 .../main/asciidoc/helloWorld/helloWorld_2.adoc  |  12 +-
 .../main/asciidoc/img/quickstart-webpage.png    | Bin 184410 -> 73601 bytes
 .../main/asciidoc/internals/pagestoring.adoc    |   5 +-
 .../main/asciidoc/resources/resources_15.adoc   |   3 +-
 .../src/main/asciidoc/security/security_4.adoc  |   2 +-
 .../main/asciidoc/security/security_4_1.adoc    |   2 +-
 wicket-user-guide/src/main/asciidoc/single.adoc |   4 -
 .../src/main/asciidoc/whyLearn/whyLearn_1.adoc  |   6 +-
 .../src/main/asciidoc/whyLearn/whyLearn_2.adoc  |   6 +-
 .../src/main/asciidoc/whyLearn/whyLearn_3.adoc  |   4 +-
 .../src/main/asciidoc/whyLearn/whyLearn_4.adoc  |   4 +-
 .../asciidoc/wicketstuff/wicketstuff_7.adoc     |   6 -
 .../wicket/util/crypt/ClassCryptFactory.java    |   2 +-
 102 files changed, 983 insertions(+), 878 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/6886c2b2/pom.xml
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/wicket/blob/6886c2b2/wicket-core/pom.xml
----------------------------------------------------------------------
diff --cc wicket-core/pom.xml
index a1ee73d,5349989..f8bb354
--- a/wicket-core/pom.xml
+++ b/wicket-core/pom.xml
@@@ -63,19 -63,9 +63,19 @@@
  			<artifactId>mockito-core</artifactId>
  		</dependency>
  		<dependency>
- 		    <groupId>com.tdunning</groupId>
- 		    <artifactId>json</artifactId>
+ 			<groupId>com.github.openjson</groupId>
+ 			<artifactId>openjson</artifactId>
  		</dependency>
 +		<dependency>
 +			<groupId>com.google.guava</groupId>
 +			<artifactId>guava</artifactId>
 +			<scope>test</scope>
 +		</dependency>
 +		<dependency>
 +			<groupId>org.apache.commons</groupId>
 +			<artifactId>commons-lang3</artifactId>
 +			<scope>test</scope>
 +		</dependency>
  	</dependencies>
  	<build>
  		<pluginManagement>


[10/10] wicket git commit: WICKET-6354 Add static getters for all supported jQuery versions

Posted by mg...@apache.org.
WICKET-6354 Add static getters for all supported jQuery versions

Use non-deprecated parent constructor


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

Branch: refs/heads/master
Commit: 312bddbc43e60b977da19291e0f349ab91e573c9
Parents: 25fb5a2
Author: Martin Tzvetanov Grigorov <mg...@apache.org>
Authored: Wed Apr 12 23:27:30 2017 +0200
Committer: Martin Tzvetanov Grigorov <mg...@apache.org>
Committed: Wed Apr 12 23:27:30 2017 +0200

----------------------------------------------------------------------
 .../org/apache/wicket/resource/DynamicJQueryResourceReference.java  | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/312bddbc/wicket-core/src/main/java/org/apache/wicket/resource/DynamicJQueryResourceReference.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/resource/DynamicJQueryResourceReference.java b/wicket-core/src/main/java/org/apache/wicket/resource/DynamicJQueryResourceReference.java
index de5582f..65768e5 100644
--- a/wicket-core/src/main/java/org/apache/wicket/resource/DynamicJQueryResourceReference.java
+++ b/wicket-core/src/main/java/org/apache/wicket/resource/DynamicJQueryResourceReference.java
@@ -49,6 +49,7 @@ public class DynamicJQueryResourceReference extends JQueryResourceReference
 
 	public DynamicJQueryResourceReference()
 	{
+		super(VERSION_2);
 	}
 
 	@Override


[06/10] wicket git commit: add equality assertions in store-page-returns test cases

Posted by mg...@apache.org.
add equality assertions in store-page-returns test cases

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

Branch: refs/heads/master
Commit: 0ebf51e96cf20886ca4301c8b424a5ab17f9a3ab
Parents: 2bae2cb
Author: manuelbarzi <ma...@192.168.1.135>
Authored: Mon Apr 3 12:05:03 2017 +0200
Committer: manuelbarzi <ma...@192.168.1.135>
Committed: Mon Apr 3 12:05:03 2017 +0200

----------------------------------------------------------------------
 .../pageStore/AsynchronousPageStoreTest.java    | 25 ++++++++++----------
 1 file changed, 13 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/0ebf51e9/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java b/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java
index d437d30..7ade857 100644
--- a/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousPageStoreTest.java
@@ -1,6 +1,7 @@
 package org.apache.wicket.pageStore;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -25,10 +26,6 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.commons.lang3.RandomUtils;
 import org.apache.wicket.page.IManageablePage;
-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.serialize.ISerializer;
 import org.apache.wicket.serialize.java.DeflatedJavaSerializer;
 import org.apache.wicket.util.file.File;
@@ -39,6 +36,7 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Stopwatch;
 
+
 /**
  * AsynchronousPageStoreTest
  * 
@@ -136,9 +134,9 @@ public class AsynchronousPageStoreTest
 
 		public String toString()
 		{
-			return "DummyPage[pageId = " + pageId + ", writeMillis = " + writeMillis
-				+ ", readMillis = " + readMillis + ", sessionId = " + sessionId + ", hashCode = "
-				+ hashCode() + "]";
+			return "DummyPage[pageId = " + pageId + ", writeMillis = " + writeMillis +
+				", readMillis = " + readMillis + ", sessionId = " + sessionId + ", hashCode = " +
+				hashCode() + "]";
 		}
 	}
 
@@ -171,9 +169,11 @@ public class AsynchronousPageStoreTest
 
 		Thread.sleep(500);
 
-		asyncPageStore.getPage(sessionId, pageId);
+		IManageablePage pageBack = asyncPageStore.getPage(sessionId, pageId);
 
 		verify(pageStore, never()).getPage(sessionId, pageId);
+
+		assertEquals(page, pageBack);
 	}
 
 	/**
@@ -205,9 +205,11 @@ public class AsynchronousPageStoreTest
 
 		Thread.sleep(1500);
 
-		asyncPageStore.getPage(sessionId, pageId);
+		IManageablePage pageBack = asyncPageStore.getPage(sessionId, pageId);
 
 		verify(pageStore, times(1)).getPage(sessionId, pageId);
+
+		assertNotEquals(page, pageBack);
 	}
 
 	/**
@@ -291,9 +293,8 @@ public class AsynchronousPageStoreTest
 
 		public String toString()
 		{
-			return "Metrics[storedPage = " + storedPage + ", storingMillis = " + storingMillis
-				+ ", restoredPage = " + restoredPage + ", restoringMillis = " + restoringMillis
-				+ "]";
+			return "Metrics[storedPage = " + storedPage + ", storingMillis = " + storingMillis +
+				", restoredPage = " + restoredPage + ", restoringMillis = " + restoringMillis + "]";
 		}
 	}