Fixes #9663tags/8.3.0.alpha1
@@ -1363,12 +1363,25 @@ public abstract class VaadinService implements Serializable { | |||
public boolean isUIActive(UI ui) { | |||
if (ui.isClosing()) { | |||
return false; | |||
} else { | |||
long now = System.currentTimeMillis(); | |||
int timeout = 1000 * getHeartbeatTimeout(); | |||
return timeout < 0 | |||
|| now - ui.getLastHeartbeatTimestamp() < timeout; | |||
} | |||
// Check for long running tasks | |||
Lock lockInstance = ui.getSession().getLockInstance(); | |||
if (lockInstance instanceof ReentrantLock) { | |||
if (((ReentrantLock) lockInstance).hasQueuedThreads()) { | |||
/* | |||
* Someone is trying to access the session. Leaving all UIs | |||
* alive for now. A possible kill decision will be made at a | |||
* later time when the session access has ended. | |||
*/ | |||
return true; | |||
} | |||
} | |||
// Check timeout | |||
long now = System.currentTimeMillis(); | |||
int timeout = 1000 * getHeartbeatTimeout(); | |||
return timeout < 0 || now - ui.getLastHeartbeatTimestamp() < timeout; | |||
} | |||
/** |
@@ -0,0 +1,47 @@ | |||
package com.vaadin.tests.core; | |||
import com.vaadin.launcher.CustomDeploymentConfiguration; | |||
import com.vaadin.launcher.CustomDeploymentConfiguration.Conf; | |||
import com.vaadin.server.VaadinRequest; | |||
import com.vaadin.server.VaadinService; | |||
import com.vaadin.ui.Button; | |||
import com.vaadin.ui.Notification; | |||
import com.vaadin.ui.Notification.Type; | |||
import com.vaadin.ui.UI; | |||
import com.vaadin.ui.VerticalLayout; | |||
@CustomDeploymentConfiguration({ | |||
@Conf(name = "heartbeatInterval", value = "2") }) | |||
public class LockingUI extends UI { | |||
public static final String LOCKING_ENDED = "Locking has ended"; | |||
public static final String ALL_OK = "All is fine"; | |||
@Override | |||
protected void init(VaadinRequest request) { | |||
Button lockButton = new Button("Lock UI for too long", e -> { | |||
int heartbeatInterval = VaadinService.getCurrent() | |||
.getDeploymentConfiguration().getHeartbeatInterval(); | |||
try { | |||
// Wait for 4 heartbeats | |||
long timeout = heartbeatInterval * 1000; | |||
for (int i = 0; i < 4; ++i) { | |||
Thread.sleep(timeout); | |||
} | |||
} catch (InterruptedException e1) { | |||
throw new RuntimeException( | |||
"Timeout should not get interrupted."); | |||
} | |||
Notification.show(LOCKING_ENDED, Type.TRAY_NOTIFICATION); | |||
}); | |||
Button checkButton = new Button("Test communication", | |||
e -> Notification.show(ALL_OK, Type.TRAY_NOTIFICATION)); | |||
lockButton.setId("lock"); | |||
checkButton.setId("check"); | |||
setContent(new VerticalLayout(lockButton, checkButton)); | |||
} | |||
} |
@@ -0,0 +1,47 @@ | |||
package com.vaadin.tests.core; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertTrue; | |||
import org.junit.Test; | |||
import com.vaadin.testbench.elements.ButtonElement; | |||
import com.vaadin.testbench.elements.NotificationElement; | |||
import com.vaadin.tests.tb3.SingleBrowserTest; | |||
public class LockingUITest extends SingleBrowserTest { | |||
@Test | |||
public void testLockingTheUIFor4HeartBeats() { | |||
openTestURL(); | |||
clickButtonAndCheckNotification("check", LockingUI.ALL_OK); | |||
clickButtonAndCheckNotification("lock", LockingUI.LOCKING_ENDED); | |||
clickButtonAndCheckNotification("check", LockingUI.ALL_OK); | |||
} | |||
private void clickButtonAndCheckNotification(String buttonId, String text) { | |||
checkNoInitialNotification(); | |||
$(ButtonElement.class).id(buttonId).click(); | |||
testBench().waitForVaadin(); | |||
checkNotification(text); | |||
} | |||
private void checkNotification(String text) { | |||
assertTrue("Notification should be displayed", | |||
$(NotificationElement.class).exists()); | |||
NotificationElement notification = $(NotificationElement.class).first(); | |||
assertEquals("Unexpected text content in Notification", text, | |||
notification.getText()); | |||
notification.close(); | |||
} | |||
private void checkNoInitialNotification() { | |||
assertFalse("Extra notification displayed", | |||
$(NotificationElement.class).exists()); | |||
} | |||
} |