From 1df59e9f5b0ca4756d2315592bb72f5818bc8b1d Mon Sep 17 00:00:00 2001 From: "Archie L. Cobbs" Date: Tue, 15 Oct 2024 16:43:39 -0500 Subject: [PATCH] fix: clear CurrentInstance before invoking new session tasks (#6349) --- .../com/vaadin/flow/server/VaadinService.java | 3 +- .../vaadin/flow/server/VaadinSessionTest.java | 65 +++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/flow-server/src/main/java/com/vaadin/flow/server/VaadinService.java b/flow-server/src/main/java/com/vaadin/flow/server/VaadinService.java index fbc7e152fce..f5cdfe901c6 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/VaadinService.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/VaadinService.java @@ -2147,11 +2147,12 @@ public void runPendingAccessTasks(VaadinSession session) { // Dump all current instances, not only the ones dumped by setCurrent Map, CurrentInstance> oldInstances = CurrentInstance .getInstances(); - CurrentInstance.setCurrent(session); try { while ((pendingAccess = session.getPendingAccessQueue() .poll()) != null) { if (!pendingAccess.isCancelled()) { + CurrentInstance.clearAll(); + CurrentInstance.setCurrent(session); pendingAccess.run(); try { diff --git a/flow-server/src/test/java/com/vaadin/flow/server/VaadinSessionTest.java b/flow-server/src/test/java/com/vaadin/flow/server/VaadinSessionTest.java index 8b615d43cc6..e83024a0456 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/VaadinSessionTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/VaadinSessionTest.java @@ -29,6 +29,8 @@ import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; @@ -189,6 +191,69 @@ public Map getParameterMap() { } + /** + * Test for issue #6349 + */ + @Test + public void testCurrentInstancePollution() throws InterruptedException { + + // Create a sync object + final AtomicInteger state = new AtomicInteger(); + + // For sleeping while we wait + final Runnable napper = () -> { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + return; + } + }; + + // We need to unlock session before running this test + session.unlock(); + try { + + // Create a thread that holds the session lock until we tell it to + // unlock; this will cause VaadinSession.access() to enqueue tasks + // instead of running them immediately. + Thread thread = new Thread(() -> { + session.accessSynchronously(() -> { + state.incrementAndGet(); + while (state.get() == 1) + napper.run(); + }); + }); + + // Start thread and wait for it to grab the lock + thread.start(); + while (state.get() == 0) + napper.run(); + + // Enqueue two session commands + session.access(() -> { + UI.setCurrent(ui); // command #1 sets current UI + state.incrementAndGet(); + }); + final AtomicReference uiRef = new AtomicReference<>(); + session.access(() -> { + uiRef.set(UI.getCurrent()); // command #2 reads current UI + state.incrementAndGet(); + }); + + // Release the session lock, which will run the queue + state.incrementAndGet(); + + // Wait for enqueued tasks to complete + while (state.get() < 4) + napper.run(); + + // Command #2 should not have seen command #1's UI + Assert.assertNull(uiRef.get()); + } finally { + session.lock(); + } + } + /** * This reproduces #14452 situation with deadlock - see diagram */