Browse Source

Fix making components visible by push (#9934)

Fix connector tracker cleanup for the case where a component is
hidden by a request and is made visible again by push.

This fixes a regression caused by #9305.

Fixes #9905
tags/8.2.0.alpha1
Henri Sara 6 years ago
parent
commit
02a666092b

+ 1
- 1
server/src/main/java/com/vaadin/server/VaadinSession.java View File

} }
} }
try { try {
ui.getConnectorTracker().cleanConnectorMap();
ui.getConnectorTracker().cleanConnectorMap(false);
} catch (AssertionError | Exception e) { } catch (AssertionError | Exception e) {
getLogger().log(Level.SEVERE, getLogger().log(Level.SEVERE,
"Exception while cleaning connector map for ui " "Exception while cleaning connector map for ui "

+ 1
- 0
server/src/main/java/com/vaadin/server/communication/UidlWriter.java View File

writePerformanceData(ui, writer); writePerformanceData(ui, writer);
} finally { } finally {
uiConnectorTracker.setWritingResponse(false); uiConnectorTracker.setWritingResponse(false);
uiConnectorTracker.cleanConnectorMap(true);
} }
} }



+ 20
- 4
server/src/main/java/com/vaadin/ui/ConnectorTracker.java View File



/** /**
* Connectors that have been unregistered and should be cleaned up the next * Connectors that have been unregistered and should be cleaned up the next
* time {@link #cleanConnectorMap()} is invoked unless they have been
* time {@link #cleanConnectorMap(boolean)} is invoked unless they have been
* registered again. * registered again.
*/ */
private final Set<ClientConnector> unregisteredConnectors = new HashSet<>(); private final Set<ClientConnector> unregisteredConnectors = new HashSet<>();
return null; return null;
} }


/**
* Cleans the connector map from all connectors that are no longer attached
* to the application if there are dirty connectors or the force flag is
* true. This should only be called by the framework.
*
* @param force
* {@code true} to force cleaning
* @since
*/
public void cleanConnectorMap(boolean force) {
if (force || !dirtyConnectors.isEmpty()) {
cleanConnectorMap();
}
}

/** /**
* Cleans the connector map from all connectors that are no longer attached * Cleans the connector map from all connectors that are no longer attached
* to the application. This should only be called by the framework. * to the application. This should only be called by the framework.
*
* @deprecated use {@link #cleanConnectorMap(boolean)} instead
*/ */
@Deprecated
public void cleanConnectorMap() { public void cleanConnectorMap() {
if (!unregisteredConnectors.isEmpty()) {
removeUnregisteredConnectors();
}
removeUnregisteredConnectors();


cleanStreamVariables(); cleanStreamVariables();



+ 0
- 43
uitest/src/main/java/com/vaadin/tests/application/MissingHierarchyDetection.java View File

*/ */
package com.vaadin.tests.application; package com.vaadin.tests.application;


import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

import com.vaadin.server.VaadinRequest; import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinSession;
import com.vaadin.tests.components.AbstractReindeerTestUIWithLog; import com.vaadin.tests.components.AbstractReindeerTestUIWithLog;
import com.vaadin.ui.Button; import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickEvent;


private CssLayout normalLayout = new CssLayout( private CssLayout normalLayout = new CssLayout(
new Label("Normal layout child")); new Label("Normal layout child"));
private List<LogRecord> pendingErrors = Collections
.synchronizedList(new ArrayList<>());


public class BrokenCssLayout extends CssLayout public class BrokenCssLayout extends CssLayout
implements SelectiveRenderer { implements SelectiveRenderer {


@Override @Override
protected void setup(VaadinRequest request) { protected void setup(VaadinRequest request) {
// Catch log messages so we can see if there is an error
Logger vaadinSessionLogger = Logger
.getLogger(VaadinSession.class.getName());
vaadinSessionLogger.addHandler(new Handler() {

@Override
public void publish(LogRecord record) {
if (record.getThrown() instanceof AssertionError) {
pendingErrors.add(record);
vaadinSessionLogger.removeHandler(this);
}
}

@Override
public void flush() {

}

@Override
public void close() throws SecurityException {

}
});
addComponent(brokenLayout); addComponent(brokenLayout);
addComponent(normalLayout); addComponent(normalLayout);
addComponent(new Button("Toggle properly", new Button.ClickListener() { addComponent(new Button("Toggle properly", new Button.ClickListener() {
toggle(false); toggle(false);
} }
})); }));
addComponent(new Button("Check for errors", new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
if (!pendingErrors.isEmpty()) {
log(pendingErrors.remove(0).getThrown().getMessage());
} else {
log("No errors");
}
}
}));
} }


private void toggle(boolean properly) { private void toggle(boolean properly) {

+ 5
- 0
uitest/src/main/java/com/vaadin/tests/components/table/TableRemovedQuicklySendsInvalidRpcCalls.java View File

return tracker.getConnector(connectorId); return tracker.getConnector(connectorId);
} }


@Override
public void cleanConnectorMap(boolean force) {
tracker.cleanConnectorMap(force);
}

@Override @Override
public void cleanConnectorMap() { public void cleanConnectorMap() {
tracker.cleanConnectorMap(); tracker.cleanConnectorMap();

+ 104
- 0
uitest/src/main/java/com/vaadin/tests/push/MakeComponentVisibleWithPush.java View File

package com.vaadin.tests.push;
import java.util.ArrayList;
import java.util.List;
import com.vaadin.annotations.Push;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.Button;
import com.vaadin.ui.Grid;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
@Push
public class MakeComponentVisibleWithPush extends AbstractTestUI {
private VerticalLayout rootLayout;
private Grid<Person> grid;
private SearchThread searchThread;
private List<Person> data;
@Override
protected void setup(VaadinRequest request) {
data = new ArrayList<>();
rootLayout = new VerticalLayout();
setContent(rootLayout);
grid = new Grid<Person>();
grid.addColumn(Person::getName);
grid.setVisible(false);
rootLayout.addComponent(grid);
Button doUpdateButton = new Button("Do Update", event -> {
try {
doUpdate();
} catch (InterruptedException e) {
}
});
rootLayout.addComponent(doUpdateButton);
}
private void doUpdate() throws InterruptedException {
cancelSuggestThread();
grid.setVisible(false);
grid.setItems(data);
UI ui = UI.getCurrent();
searchThread = new SearchThread(ui);
searchThread.start();
}
class SearchThread extends Thread {
private UI ui;
public SearchThread(UI ui) {
this.ui = ui;
}
@Override
public void run() {
data = new ArrayList<Person>(data);
data.add(new Person("Person " + (data.size() + 1)));
if (!searchThread.isInterrupted()) {
ui.access(() -> {
grid.setItems(data);
grid.setVisible(true);
});
}
}
}
private void cancelSuggestThread() {
if ((searchThread != null) && !searchThread.isInterrupted()) {
searchThread.interrupt();
searchThread = null;
}
}
class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}

+ 1
- 6
uitest/src/test/java/com/vaadin/tests/application/MissingHierarchyDetectionTest.java View File

ButtonElement toggleImproperly = $(ButtonElement.class) ButtonElement toggleImproperly = $(ButtonElement.class)
.caption("Toggle improperly").first(); .caption("Toggle improperly").first();
toggleImproperly.click(); toggleImproperly.click();

$(ButtonElement.class).caption("Check for errors").first().click();
Assert.assertTrue(
"No error was logged for the missing hierarchy change event",
getLogRow(0).contains(
"is no longer visible to the client, but no corresponding hierarchy change was sent."));
assertSystemNotification();
} }
} }

+ 41
- 0
uitest/src/test/java/com/vaadin/tests/push/MakeComponentVisibleWithPushTest.java View File

/*
* Copyright 2000-2016 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.push;

import org.junit.Assert;
import org.junit.Test;

import com.vaadin.testbench.elements.ButtonElement;
import com.vaadin.testbench.elements.GridElement;
import com.vaadin.tests.tb3.SingleBrowserTest;

public class MakeComponentVisibleWithPushTest extends SingleBrowserTest {

@Test
public void showingHiddenComponentByPushWorks() {
setDebug(true);
openTestURL();

$(ButtonElement.class).first().click();
Assert.assertEquals("Unexpected row count", 1,
$(GridElement.class).first().getRowCount());
$(ButtonElement.class).first().click();
Assert.assertEquals("Unexpected row count", 2,
$(GridElement.class).first().getRowCount());

assertNoErrorNotifications();
}
}

Loading…
Cancel
Save