]> source.dussan.org Git - vaadin-framework.git/commitdiff
Don't process push messages until init JSON is processed (#11529)
authorLeif Åstrand <leif@vaadin.com>
Wed, 10 Apr 2013 07:21:59 +0000 (10:21 +0300)
committerLeif Åstrand <leif@vaadin.com>
Wed, 10 Apr 2013 07:21:59 +0000 (10:21 +0300)
* The test is not running reliably in all browsers, but assuming this is
a symptom of other push issues and not related to this particular bug.

Change-Id: I848b57502aa01467b0f60624cf599247ec76f32f

client/src/com/vaadin/client/ApplicationConnection.java
uitest/src/com/vaadin/tests/push/PushFromInit.html [new file with mode: 0644]
uitest/src/com/vaadin/tests/push/PushFromInit.java [new file with mode: 0644]

index 0341a9d5c41fd3eae99a661b437e73dafe261795..2fa82c6004b9f4149d245bda7d5d9290ac659eeb 100644 (file)
@@ -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 (file)
index 0000000..d009eb3
--- /dev/null
@@ -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&amp;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 (file)
index 0000000..c43739e
--- /dev/null
@@ -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);
+    }
+
+}