From f8aacf7c53d2e758e431588f44185b583fad8cb6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Leif=20=C3=85strand?= Date: Sun, 14 Jun 2015 15:36:33 +0300 Subject: [PATCH] Allow beforeClientResponse to change hierarchy or dirtyness (#18268) Change-Id: I6a1ae23c1dd67f8889479a1069f260fa736bbd83 --- .../com/vaadin/server/ClientConnector.java | 4 -- .../server/communication/UidlWriter.java | 38 +++++++--- .../ChangeHierarchyBeforeResponse.java | 71 +++++++++++++++++++ .../ChangeHierarchyBeforeResponseTest.java | 43 +++++++++++ 4 files changed, 143 insertions(+), 13 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/abstractcomponent/ChangeHierarchyBeforeResponse.java create mode 100644 uitest/src/com/vaadin/tests/components/abstractcomponent/ChangeHierarchyBeforeResponseTest.java diff --git a/server/src/com/vaadin/server/ClientConnector.java b/server/src/com/vaadin/server/ClientConnector.java index b784aa5d35..63483bc254 100644 --- a/server/src/com/vaadin/server/ClientConnector.java +++ b/server/src/com/vaadin/server/ClientConnector.java @@ -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. - *

- * This method must not alter the component hierarchy in any way. Calling - * {@link #markAsDirty()} from this method will have no effect. - *

* * @param initial * true if the client-side connector will be created diff --git a/server/src/com/vaadin/server/communication/UidlWriter.java b/server/src/com/vaadin/server/communication/UidlWriter.java index 3b2caba55b..00a65d3877 100644 --- a/server/src/com/vaadin/server/communication/UidlWriter.java +++ b/server/src/com/vaadin/server/communication/UidlWriter.java @@ -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 dirtyVisibleConnectors = ui - .getConnectorTracker().getDirtyVisibleConnectors(); + Set processedConnectors = new HashSet(); + LegacyCommunicationManager manager = session.getCommunicationManager(); // Paints components ConnectorTracker uiConnectorTracker = ui.getConnectorTracker(); getLogger().log(Level.FINE, "* Creating response to client"); + while (true) { + ArrayList connectorsToProcess = new ArrayList(); + 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 index 0000000000..e6daf8356c --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/abstractcomponent/ChangeHierarchyBeforeResponse.java @@ -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 index 0000000000..485e218a68 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/abstractcomponent/ChangeHierarchyBeforeResponseTest.java @@ -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()); + } +} -- 2.39.5