]> source.dussan.org Git - vaadin-framework.git/commitdiff
Allow beforeClientResponse to change hierarchy or dirtyness (#18268)
authorLeif Åstrand <leif@vaadin.com>
Sun, 14 Jun 2015 12:36:33 +0000 (15:36 +0300)
committerVaadin Code Review <review@vaadin.com>
Wed, 17 Jun 2015 12:32:18 +0000 (12:32 +0000)
Change-Id: I6a1ae23c1dd67f8889479a1069f260fa736bbd83

server/src/com/vaadin/server/ClientConnector.java
server/src/com/vaadin/server/communication/UidlWriter.java
uitest/src/com/vaadin/tests/components/abstractcomponent/ChangeHierarchyBeforeResponse.java [new file with mode: 0644]
uitest/src/com/vaadin/tests/components/abstractcomponent/ChangeHierarchyBeforeResponseTest.java [new file with mode: 0644]

index b784aa5d35cdb9df4b0e66f66c2365982eb2d495..63483bc2540d0489ec27f29106f6387e63774b6e 100644 (file)
@@ -256,10 +256,6 @@ public interface ClientConnector extends Connector {
      * client. Gives the connector an opportunity to set computed/dynamic state
      * values or to invoke last minute RPC methods depending on other component
      * features.
-     * <p>
-     * This method must not alter the component hierarchy in any way. Calling
-     * {@link #markAsDirty()} from this method will have no effect.
-     * </p>
      * 
      * @param initial
      *            <code>true</code> if the client-side connector will be created
index 3b2caba55b1e8d98d52ab0a0730a402384579cbe..00a65d3877cc27a2f8b734f694b1ddd29c0b07e9 100644 (file)
@@ -23,7 +23,9 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -81,22 +83,40 @@ public class UidlWriter implements Serializable {
         // to write out
         service.runPendingAccessTasks(session);
 
-        ArrayList<ClientConnector> dirtyVisibleConnectors = ui
-                .getConnectorTracker().getDirtyVisibleConnectors();
+        Set<ClientConnector> processedConnectors = new HashSet<ClientConnector>();
+
         LegacyCommunicationManager manager = session.getCommunicationManager();
         // Paints components
         ConnectorTracker uiConnectorTracker = ui.getConnectorTracker();
         getLogger().log(Level.FINE, "* Creating response to client");
 
+        while (true) {
+            ArrayList<ClientConnector> connectorsToProcess = new ArrayList<ClientConnector>();
+            for (ClientConnector c : uiConnectorTracker.getDirtyConnectors()) {
+                if (!processedConnectors.contains(c)
+                        && LegacyCommunicationManager
+                                .isConnectorVisibleToClient(c)) {
+                    connectorsToProcess.add(c);
+                }
+            }
+
+            if (connectorsToProcess.isEmpty()) {
+                break;
+            }
+
+            for (ClientConnector connector : connectorsToProcess) {
+                boolean initialized = uiConnectorTracker
+                        .isClientSideInitialized(connector);
+                processedConnectors.add(connector);
+
+                connector.beforeClientResponse(!initialized);
+            }
+        }
+
         getLogger().log(
                 Level.FINE,
-                "Found " + dirtyVisibleConnectors.size()
+                "Found " + processedConnectors.size()
                         + " dirty connectors to paint");
-        for (ClientConnector connector : dirtyVisibleConnectors) {
-            boolean initialized = uiConnectorTracker
-                    .isClientSideInitialized(connector);
-            connector.beforeClientResponse(!initialized);
-        }
 
         uiConnectorTracker.setWritingResponse(true);
         try {
@@ -292,7 +312,7 @@ public class UidlWriter implements Serializable {
 
             session.getDragAndDropService().printJSONResponse(writer);
 
-            for (ClientConnector connector : dirtyVisibleConnectors) {
+            for (ClientConnector connector : processedConnectors) {
                 uiConnectorTracker.markClientSideInitialized(connector);
             }
 
diff --git a/uitest/src/com/vaadin/tests/components/abstractcomponent/ChangeHierarchyBeforeResponse.java b/uitest/src/com/vaadin/tests/components/abstractcomponent/ChangeHierarchyBeforeResponse.java
new file mode 100644 (file)
index 0000000..e6daf83
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2000-2014 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.abstractcomponent;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.CssLayout;
+import com.vaadin.ui.Label;
+
+public class ChangeHierarchyBeforeResponse extends AbstractTestUI {
+    private CssLayout layout = new CssLayout() {
+        @Override
+        public void beforeClientResponse(boolean initial) {
+            super.beforeClientResponse(initial);
+            if (initial) {
+                addComponent(buttonToAdd);
+                removeComponent(labelToRemove);
+            }
+        }
+    };
+
+    private Button buttonToAdd = new Button("Added from beforeClientResponse",
+            new Button.ClickListener() {
+                @Override
+                public void buttonClick(ClickEvent event) {
+                    layout.addComponent(labelToRemove);
+                }
+            }) {
+        @Override
+        public void beforeClientResponse(boolean initial) {
+            super.beforeClientResponse(initial);
+            setCaption("Add label to layout");
+        }
+    };
+
+    private Label labelToRemove = new Label("Label to remove") {
+        int count = 0;
+
+        @Override
+        public void beforeClientResponse(boolean initial) {
+            super.beforeClientResponse(initial);
+            if (initial) {
+                count++;
+                setValue("Initial count: " + count);
+            }
+        }
+    };
+
+    @Override
+    protected void setup(VaadinRequest request) {
+        layout.addComponent(labelToRemove);
+
+        addComponent(layout);
+    }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/abstractcomponent/ChangeHierarchyBeforeResponseTest.java b/uitest/src/com/vaadin/tests/components/abstractcomponent/ChangeHierarchyBeforeResponseTest.java
new file mode 100644 (file)
index 0000000..485e218
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2000-2014 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.abstractcomponent;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.testbench.elements.LabelElement;
+import com.vaadin.tests.tb3.SingleBrowserTest;
+
+public class ChangeHierarchyBeforeResponseTest extends SingleBrowserTest {
+    @Test
+    public void testHierarchyChangeBeforeResponse() {
+        openTestURL();
+
+        ButtonElement button = $(ButtonElement.class).first();
+
+        Assert.assertEquals(
+                "Button caption should change by its own beforeClientResponse",
+                "Add label to layout", button.getText());
+
+        button.click();
+
+        LabelElement label = $(LabelElement.class).all().get(1);
+
+        Assert.assertEquals("Label should have been considered initial twice",
+                "Initial count: 2", label.getText());
+    }
+}