From: Leif Åstrand Date: Tue, 23 Jul 2013 13:12:49 +0000 (+0300) Subject: Verify the connector hierarchy if assertions are enabled (#12271) X-Git-Tag: 7.1.2~20 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=a53d4876f2e1b0edf34444e118c79b881f5549f9;p=vaadin-framework.git Verify the connector hierarchy if assertions are enabled (#12271) Change-Id: I87632abe9d86927b7ba4254724fedfdb04513205 --- diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index 236417f23b..0b64f56c3e 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -2000,12 +2000,15 @@ public class ApplicationConnection { .getConnector(childConnectorId); if (childConnector == null) { VConsole.error("Hierarchy claims that " - + childConnectorId + " is a child for " - + connectorId + " (" + + childConnectorId + + " is a child for " + + connectorId + + " (" + parentConnector.getClass().getName() + ") but no connector with id " + childConnectorId - + " has been registered"); + + " has been registered. " + + "More information might be available in the server-side log if assertions are enabled"); continue; } newChildren.add(childConnector); diff --git a/server/src/com/vaadin/ui/ConnectorTracker.java b/server/src/com/vaadin/ui/ConnectorTracker.java index c2aeebcd44..0f8ec60104 100644 --- a/server/src/com/vaadin/ui/ConnectorTracker.java +++ b/server/src/com/vaadin/ui/ConnectorTracker.java @@ -22,6 +22,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedList; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -271,6 +272,12 @@ public class ConnectorTracker implements Serializable { } unregisteredConnectors.clear(); + // Do this expensive check only with assertions enabled + assert isHierarchyComplete() : "The connector hierarchy is corrupted. " + + "Check for missing calls to super.setParent(), super.attach() and super.detach() " + + "and that all custom component containers call child.setParent(this) when a child is added and child.setParent(null) when the child is no longer used. " + + "See previous log messages for details."; + // remove detached components from paintableIdMap so they // can be GC'ed Iterator iterator = connectorIdToConnector.keySet().iterator(); @@ -313,6 +320,49 @@ public class ConnectorTracker implements Serializable { cleanStreamVariables(); } + private boolean isHierarchyComplete() { + boolean noErrors = true; + + Set danglingConnectors = new HashSet( + connectorIdToConnector.values()); + + LinkedList stack = new LinkedList(); + stack.add(uI); + while (!stack.isEmpty()) { + ClientConnector connector = stack.pop(); + danglingConnectors.remove(connector); + + Iterable children = AbstractClientConnector + .getAllChildrenIterable(connector); + for (ClientConnector child : children) { + stack.add(child); + + if (child.getParent() != connector) { + noErrors = false; + getLogger() + .log(Level.WARNING, + "{0} claims that {1} is its child, but the child claims {2} is its parent.", + new Object[] { + getConnectorString(connector), + getConnectorString(child), + getConnectorString(child + .getParent()) }); + } + } + } + + for (ClientConnector dangling : danglingConnectors) { + noErrors = false; + getLogger() + .log(Level.WARNING, + "{0} claims that {1} is its parent, but the parent does not acknowledge the parenthood.", + new Object[] { getConnectorString(dangling), + getConnectorString(dangling.getParent()) }); + } + + return noErrors; + } + /** * Finds the uI that the connector is attached to. *