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 2023/05/04 18:37:11 UTC
[wicket] branch master updated: WICKET-6966, WICKET-7013: prevent unsynchronized access to pages (#587)
This is an automated email from the ASF dual-hosted git repository.
mgrigorov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/wicket.git
The following commit(s) were added to refs/heads/master by this push:
new 125fe8ab96 WICKET-6966, WICKET-7013: prevent unsynchronized access to pages (#587)
125fe8ab96 is described below
commit 125fe8ab96ce54565aaadaa3ba911b57439b85e1
Author: dr0ps <32...@users.noreply.github.com>
AuthorDate: Thu May 4 20:37:05 2023 +0200
WICKET-6966, WICKET-7013: prevent unsynchronized access to pages (#587)
* Wicket-6966: prevent unsynchronized access to pages
* Added concurrency test case
---------
Co-authored-by: dr0ps <dr...@users.noreply.github.com>
---
.../wicket/pageStore/InSessionPageStore.java | 2 +-
.../InSessionPageStoreConcurrencyTest.java | 131 +++++++++++++++++++++
2 files changed, 132 insertions(+), 1 deletion(-)
diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/InSessionPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/InSessionPageStore.java
index b8c432a558..54d2fa8a9c 100644
--- a/wicket-core/src/main/java/org/apache/wicket/pageStore/InSessionPageStore.java
+++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/InSessionPageStore.java
@@ -261,7 +261,7 @@ public class InSessionPageStore implements IPageStore
/**
* Serialize pages before writing to output.
*/
- private void writeObject(final ObjectOutputStream output) throws IOException
+ private synchronized void writeObject(final ObjectOutputStream output) throws IOException
{
// handle non-serialized pages
for (int p = 0; p < pages.size(); p++)
diff --git a/wicket-core/src/test/java/org/apache/wicket/pageStore/InSessionPageStoreConcurrencyTest.java b/wicket-core/src/test/java/org/apache/wicket/pageStore/InSessionPageStoreConcurrencyTest.java
new file mode 100644
index 0000000000..75594096e2
--- /dev/null
+++ b/wicket-core/src/test/java/org/apache/wicket/pageStore/InSessionPageStoreConcurrencyTest.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.pageStore;
+
+import org.apache.commons.io.output.NullOutputStream;
+import org.apache.wicket.IPageManagerProvider;
+import org.apache.wicket.mock.MockApplication;
+import org.apache.wicket.page.PageManager;
+import org.apache.wicket.protocol.http.WebApplication;
+import org.apache.wicket.protocol.http.mock.MockHttpSession;
+import org.apache.wicket.protocol.http.mock.MockServletContext;
+import org.apache.wicket.serialize.java.JavaSerializer;
+import org.apache.wicket.util.tester.WicketTester;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+public class InSessionPageStoreConcurrencyTest
+{
+ public static class PageStoringWicketTester extends WicketTester
+ {
+ final static InSessionPageStore session = new InSessionPageStore(10, new JavaSerializer("key"));
+
+ public PageStoringWicketTester(final WebApplication application, final boolean init)
+ {
+ super(application, init);
+ }
+
+ @Override
+ protected IPageManagerProvider newTestPageManagerProvider()
+ {
+ return () ->
+ new PageManager(session);
+ }
+ }
+
+ @Test
+ public void testConcurrentModifications() throws Exception
+ {
+ final WebApplication application = new MockApplication();
+
+ final MockHttpSession httpSession = new MockHttpSession(new MockServletContext(application, ""));
+
+ //prepare servlet context
+ final WicketTester wicketTester = new PageStoringWicketTester(application, true)
+ {
+ @Override
+ public MockHttpSession getHttpSession()
+ {
+ return httpSession;
+ }
+ };
+ wicketTester.executeUrl("/");
+
+
+ ExecutorService executor = Executors.newFixedThreadPool(1000);
+
+ Callable<Void> executeURLTask = () -> {
+ final WicketTester parallelWicketTester;
+ synchronized (application)
+ {
+ parallelWicketTester = new PageStoringWicketTester(application, false)
+ {
+ @Override
+ public MockHttpSession getHttpSession()
+ {
+ return httpSession;
+ }
+ };
+ }
+
+ parallelWicketTester.executeUrl("/");
+ return null;
+ };
+
+ Callable<Void> serializeSessionTask = () -> {
+ final NullOutputStream nullOutputStream = NullOutputStream.NULL_OUTPUT_STREAM;
+ try(final ObjectOutputStream objectOutputStream = new ObjectOutputStream(nullOutputStream))
+ {
+ objectOutputStream.writeObject(wicketTester.getSession());
+ }
+ catch(final IOException e)
+ {
+ throw new RuntimeException(e);
+ }
+ return null;
+ };
+
+ var tasks = Stream.concat(
+ IntStream.rangeClosed(1, 500).mapToObj(i -> serializeSessionTask),
+ IntStream.rangeClosed(1, 500).mapToObj(i -> executeURLTask)
+ ).collect(Collectors.toList());
+
+ var futures = executor.invokeAll(tasks);
+
+ futures.forEach(
+ exceptionFuture -> {
+ try
+ {
+ exceptionFuture.get();
+ }
+ catch (InterruptedException| ExecutionException e)
+ {
+ throw new RuntimeException(e);
+ }
+ });
+ }
+
+}