diff options
-rw-r--r-- | client/src/com/vaadin/client/ApplicationConnection.java | 65 | ||||
-rw-r--r-- | uitest/src/com/vaadin/tests/push/PushFromInit.html | 32 | ||||
-rw-r--r-- | uitest/src/com/vaadin/tests/push/PushFromInit.java | 36 |
3 files changed, 128 insertions, 5 deletions
diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index 0341a9d5c4..2fa82c6004 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -183,6 +183,19 @@ public class ApplicationConnection { protected boolean applicationRunning = false; + /** + * Keep track of whether the initialization JSON has been handled. We should + * not process any push messages until the initial JSON has been processed. + */ + private boolean initJsonHandled = false; + + /** + * Keep track of any push messages that arrive before + * {@link #initJsonHandled} is set to true. + */ + private JsArrayString incommingPushMessageQueue = JsArrayString + .createArray().cast(); + private boolean hasActiveRequest = false; /** @@ -1114,6 +1127,26 @@ public class ApplicationConnection { checkForPendingVariableBursts(); runPostRequestHooks(configuration.getRootPanelId()); } + + if (!initJsonHandled) { + /* + * Assume that the first request that is fully handled is the one + * with the initialization data. + */ + initJsonHandled = true; + + int queueLength = incommingPushMessageQueue.length(); + if (queueLength > 0) { + VConsole.log("Init handled, processing " + queueLength + + " enqueued messages"); + for (int i = 0; i < queueLength; i++) { + handlePushMessage(incommingPushMessageQueue.get(i)); + } + incommingPushMessageQueue.setLength(0); + } + + } + // deferring to avoid flickering Scheduler.get().scheduleDeferred(new Command() { @Override @@ -1258,6 +1291,14 @@ public class ApplicationConnection { return; } + /* + * Lock response handling to avoid a situation where something pushed + * from the server gets processed while waiting for e.g. lazily loaded + * connectors that are needed for processing the current message. + */ + final Object lock = new Object(); + suspendReponseHandling(lock); + VConsole.log("Handling message from server"); eventBus.fireEvent(new ResponseHandlingStartedEvent(this)); @@ -1476,6 +1517,7 @@ public class ApplicationConnection { // not sent asynchronously endRequest(); } + resumeResponseHandling(lock); if (Profiler.isEnabled()) { Scheduler.get().scheduleDeferred(new ScheduledCommand() { @@ -3264,11 +3306,19 @@ public class ApplicationConnection { * suspended. */ private void handlePendingMessages() { - for (PendingUIDLMessage pending : pendingUIDLMessages) { - handleUIDLMessage(pending.getStart(), pending.getJsonText(), - pending.getJson()); + if (!pendingUIDLMessages.isEmpty()) { + /* + * Clear the list before processing enqueued messages to support + * reentrancy + */ + List<PendingUIDLMessage> pendingMessages = pendingUIDLMessages; + pendingUIDLMessages = new ArrayList<PendingUIDLMessage>(); + + for (PendingUIDLMessage pending : pendingMessages) { + handleReceivedJSONMessage(pending.getStart(), + pending.getJsonText(), pending.getJson()); + } } - pendingUIDLMessages.clear(); } private boolean handleErrorInDelegate(String details, int statusCode) { @@ -3348,6 +3398,11 @@ public class ApplicationConnection { } public void handlePushMessage(String message) { - handleJSONText(message, 200); + if (initJsonHandled) { + handleJSONText(message, 200); + } else { + VConsole.log("Enqueuing push message has init has not yet been handled"); + incommingPushMessageQueue.push(message); + } } } diff --git a/uitest/src/com/vaadin/tests/push/PushFromInit.html b/uitest/src/com/vaadin/tests/push/PushFromInit.html new file mode 100644 index 0000000000..d009eb3baf --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/PushFromInit.html @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="" /> +<title>New Test</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">New Test</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run-push/com.vaadin.tests.push.PushFromInit?debug&restartApplication</td> + <td></td> +</tr> +<tr> + <td>waitForText</td> + <td>vaadin=runpushcomvaadintestspushPushFromInit::PID_SLog_row_1</td> + <td>1. Logged in init</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runpushcomvaadintestspushPushFromInit::PID_SLog_row_0</td> + <td>2. Logged from background thread started in init</td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/uitest/src/com/vaadin/tests/push/PushFromInit.java b/uitest/src/com/vaadin/tests/push/PushFromInit.java new file mode 100644 index 0000000000..c43739ec04 --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/PushFromInit.java @@ -0,0 +1,36 @@ +package com.vaadin.tests.push; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.ui.Button; + +public class PushFromInit extends AbstractTestUIWithLog { + + @Override + protected void setup(VaadinRequest request) { + new Thread() { + @Override + public void run() { + runSafely(new Runnable() { + @Override + public void run() { + log("Logged from background thread started in init"); + } + }); + } + }.start(); + log("Logged in init"); + addComponent(new Button("Sync")); + } + + @Override + protected String getTestDescription() { + return "Pusing something to a newly created UI should not cause race conditions"; + } + + @Override + protected Integer getTicketNumber() { + return Integer.valueOf(11529); + } + +} |