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 1959f249ec8..a1e41d15fcc 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 @@ -2035,11 +2035,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 47b81d7cd6f..6fed0d73d8b 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 @@ -23,6 +23,8 @@ import java.util.concurrent.Future; 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; @@ -161,6 +163,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 */