From 4d7f190b7f36a10b16e74b1dab8ed0a274841ae1 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Wed, 22 May 2013 15:56:29 +0300 Subject: Make access() enqueue the runnable if the session is locked (#11897) Change-Id: If162e81a29bbc982857e2a165a983e161ea837ee --- .../vaadin/tests/applicationcontext/CloseUI.java | 2 +- .../applicationcontext/UIRunSafelyThread.java | 2 +- .../com/vaadin/tests/components/ui/UiAccess.html | 127 +++++++++++ .../com/vaadin/tests/components/ui/UiAccess.java | 235 +++++++++++++++++++++ 4 files changed, 364 insertions(+), 2 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/ui/UiAccess.html create mode 100644 uitest/src/com/vaadin/tests/components/ui/UiAccess.java (limited to 'uitest') diff --git a/uitest/src/com/vaadin/tests/applicationcontext/CloseUI.java b/uitest/src/com/vaadin/tests/applicationcontext/CloseUI.java index bec8c0a10f..c88f482a7b 100644 --- a/uitest/src/com/vaadin/tests/applicationcontext/CloseUI.java +++ b/uitest/src/com/vaadin/tests/applicationcontext/CloseUI.java @@ -119,7 +119,7 @@ public class CloseUI extends AbstractTestUI { @Override public void run() { - ui.access(new Runnable() { + ui.accessSynchronously(new Runnable() { @Override public void run() { diff --git a/uitest/src/com/vaadin/tests/applicationcontext/UIRunSafelyThread.java b/uitest/src/com/vaadin/tests/applicationcontext/UIRunSafelyThread.java index ddc0f28664..c9af2c000d 100644 --- a/uitest/src/com/vaadin/tests/applicationcontext/UIRunSafelyThread.java +++ b/uitest/src/com/vaadin/tests/applicationcontext/UIRunSafelyThread.java @@ -11,7 +11,7 @@ public abstract class UIRunSafelyThread extends Thread { @Override public void run() { - ui.access(new Runnable() { + ui.accessSynchronously(new Runnable() { @Override public void run() { diff --git a/uitest/src/com/vaadin/tests/components/ui/UiAccess.html b/uitest/src/com/vaadin/tests/components/ui/UiAccess.html new file mode 100644 index 0000000000..664b15c16f --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/ui/UiAccess.html @@ -0,0 +1,127 @@ + + + + + + +New Test + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
New Test
open/run/com.vaadin.tests.components.ui.UiAccess?restartApplication
clickvaadin=runcomvaadintestscomponentsuiUiAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[0]/VButton[0]/domChild[0]/domChild[0]
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_2exact:0. Access from UI thread future is done? false
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_11. Access from UI thread is run
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_0exact:2. beforeClientResponse future is done? true
clickvaadin=runcomvaadintestscomponentsuiUiAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[1]/VButton[0]/domChild[0]/domChild[0]
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_10. Initial background message
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_0exact:1. Thread has current response? false
waitForTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_40. Initial background message
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_2exact:2. Thread got lock, inital future done? true
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_1exact:3. Access has current response? true
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_0exact:4. Thread is still alive? false
clickvaadin=runcomvaadintestscomponentsuiUiAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_20. Throwing exception in access
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_1exact:1. firstFuture is done? true
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_02. Got exception from firstFuture: java.lang.RuntimeException: Catch me if you can
clickvaadin=runcomvaadintestscomponentsuiUiAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_00. future was cancled, should not start
clickvaadin=runcomvaadintestscomponentsuiUiAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[4]/VButton[0]/domChild[0]/domChild[0]
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_20. Waiting for thread to start
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_11. Thread started, waiting for interruption
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_02. I was interrupted
+ + diff --git a/uitest/src/com/vaadin/tests/components/ui/UiAccess.java b/uitest/src/com/vaadin/tests/components/ui/UiAccess.java new file mode 100644 index 0000000000..c68da6ee54 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/ui/UiAccess.java @@ -0,0 +1,235 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed 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 com.vaadin.tests.components.ui; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.locks.ReentrantLock; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.server.VaadinService; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; + +public class UiAccess extends AbstractTestUIWithLog { + + private Future checkFromBeforeClientResponse; + + @Override + protected void setup(VaadinRequest request) { + addComponent(new Button("Access from UI thread", + new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + log.clear(); + // Ensure beforeClientResponse is invoked + markAsDirty(); + checkFromBeforeClientResponse = access(new Runnable() { + @Override + public void run() { + log("Access from UI thread is run"); + } + }); + log("Access from UI thread future is done? " + + checkFromBeforeClientResponse.isDone()); + } + })); + addComponent(new Button("Access from background thread", + new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + log.clear(); + final CountDownLatch latch = new CountDownLatch(1); + + new Thread() { + @Override + public void run() { + final boolean threadHasCurrentResponse = VaadinService + .getCurrentResponse() != null; + // session is locked by request thread at this + // point + final Future initialFuture = access(new Runnable() { + @Override + public void run() { + log("Initial background message"); + log("Thread has current response? " + + threadHasCurrentResponse); + } + }); + + // Let request thread continue + latch.countDown(); + + // Wait until thread can be locked + while (!getSession().getLockInstance() + .tryLock()) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + try { + log("Thread got lock, inital future done? " + + initialFuture.isDone()); + setPollInterval(-1); + } finally { + getSession().unlock(); + } + final Thread thisThread = this; + access(new Runnable() { + @Override + public void run() { + log("Access has current response? " + + (VaadinService + .getCurrentResponse() != null)); + log("Thread is still alive? " + + thisThread.isAlive()); + } + }); + } + }.start(); + + // Wait for thread to do initialize before continuing + try { + latch.await(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + setPollInterval(3000); + } + })); + addComponent(new Button("Access throwing exception", + new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + log.clear(); + final Future firstFuture = access(new Runnable() { + @Override + public void run() { + log("Throwing exception in access"); + throw new RuntimeException( + "Catch me if you can"); + } + }); + access(new Runnable() { + @Override + public void run() { + log("firstFuture is done? " + + firstFuture.isDone()); + try { + firstFuture.get(); + log("Should not get here"); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } catch (ExecutionException e) { + log("Got exception from firstFuture: " + + e.getMessage()); + } + } + }); + } + })); + addComponent(new Button("Cancel future before started", + new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + log.clear(); + Future future = access(new Runnable() { + @Override + public void run() { + log("Should not get here"); + } + }); + future.cancel(false); + log("future was cancled, should not start"); + } + })); + addComponent(new Button("Cancel running future", + new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + log.clear(); + final ReentrantLock interruptLock = new ReentrantLock(); + + final Future future = access(new Runnable() { + @Override + public void run() { + log("Waiting for thread to start"); + while (!interruptLock.isLocked()) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + log("Premature interruption"); + throw new RuntimeException(e); + } + } + + log("Thread started, waiting for interruption"); + try { + interruptLock.lockInterruptibly(); + } catch (InterruptedException e) { + log("I was interrupted"); + } + } + }); + + new Thread() { + @Override + public void run() { + interruptLock.lock(); + // Wait until UI thread has started waiting for + // the lock + while (!interruptLock.hasQueuedThreads()) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + future.cancel(true); + } + }.start(); + } + })); + } + + @Override + public void beforeClientResponse(boolean initial) { + if (checkFromBeforeClientResponse != null) { + log("beforeClientResponse future is done? " + + checkFromBeforeClientResponse.isDone()); + checkFromBeforeClientResponse = null; + } + } + + @Override + protected String getTestDescription() { + return "Test for various ways of using UI.access"; + } + + @Override + protected Integer getTicketNumber() { + return Integer.valueOf(11897); + } + +} -- cgit v1.2.3