.getJavascriptConnectorHelper()
.setNativeState(
stateJson.getJavaScriptObject());
}
SharedState state = connector.getState();
Profiler.enter("updateConnectorState decodeValue");
JsonDecoder.decodeValue(new Type(state.getClass()
.getName(), null), stateJson, state,
ApplicationConnection.this);
Profiler.leave("updateConnectorState decodeValue");
if (Profiler.isEnabled()) {
Profiler.leave("Decode connector state "
+ Util.getSimpleName(connector));
}
Profiler.enter("updateConnectorState create event");
boolean isNewConnector = remainingNewConnectors
.contains(connectorId);
if (isNewConnector) {
remainingNewConnectors.remove(connectorId);
}
StateChangeEvent event = new StateChangeEvent(
connector, stateJson, isNewConnector);
events.add(event);
Profiler.leave("updateConnectorState create event");
Profiler.leave("updateConnectorState inner loop");
}
} catch (final Throwable e) {
VConsole.error(e);
}
}
Profiler.enter("updateConnectorState newWithoutState");
// Fire events for properties using the default value for newly
// created connectors even if there were no state changes
JsArrayString dump = remainingNewConnectors.dump();
int length = dump.length();
for (int i = 0; i < length; i++) {
String connectorId = dump.get(i);
ServerConnector connector = connectorMap
.getConnector(connectorId);
StateChangeEvent event = new StateChangeEvent(connector,
new JSONObject(), true);
events.add(event);
}
Profiler.leave("updateConnectorState newWithoutState");
Profiler.leave("updateConnectorState");
return events;
}
/**
* Updates the connector hierarchy and returns a list of events that
* should be fired after update of the hierarchy and the state is
* done.
*
* @param json
* The JSON containing the hierarchy information
* @return A collection of events that should be fired when update
* of hierarchy and state is complete and a list of all
* connectors for which the parent has changed
*/
private ConnectorHierarchyUpdateResult updateConnectorHierarchy(
ValueMap json) {
ConnectorHierarchyUpdateResult result = new ConnectorHierarchyUpdateResult();
VConsole.log(" * Updating connector hierarchy");
if (!json.containsKey("hierarchy")) {
return result;
}
Profiler.enter("updateConnectorHierarchy");
FastStringSet maybeDetached = FastStringSet.create();
ValueMap hierarchies = json.getValueMap("hierarchy");
JsArrayString hierarchyKeys = hierarchies.getKeyArray();
for (int i = 0; i < hierarchyKeys.length(); i++) {
try {
Profiler.enter("updateConnectorHierarchy hierarchy entry");
String connectorId = hierarchyKeys.get(i);
ServerConnector parentConnector = connectorMap
.getConnector(connectorId);
JsArrayString childConnectorIds = hierarchies
.getJSStringArray(connectorId);
int childConnectorSize = childConnectorIds.length();
Profiler.enter("updateConnectorHierarchy find new connectors");
List<ServerConnector> newChildren = new ArrayList<ServerConnector>();
List<ComponentConnector> newComponents = new ArrayList<ComponentConnector>();
for (int connectorIndex = 0; connectorIndex < childConnectorSize; connectorIndex++) {
String childConnectorId = childConnectorIds
.get(connectorIndex);
ServerConnector childConnector = connectorMap
.getConnector(childConnectorId);
if (childConnector == null) {
VConsole.error("Hierarchy claims that "
+ childConnectorId
+ " is a child for "
+ connectorId
+ " ("
+ parentConnector.getClass().getName()
+ ") but no connector with id "
+ childConnectorId
+ " has been registered. "
+ "More information might be available in the server-side log if assertions are enabled");
continue;
}
newChildren.add(childConnector);
if (childConnector instanceof ComponentConnector) {
newComponents
.add((ComponentConnector) childConnector);
} else if (!(childConnector instanceof AbstractExtensionConnector)) {
throw new IllegalStateException(
Util.getConnectorString(childConnector)
+ " is not a ComponentConnector nor an AbstractExtensionConnector");
}
if (childConnector.getParent() != parentConnector) {
childConnector.setParent(parentConnector);
result.parentChangedIds.add(childConnectorId);
// Not detached even if previously removed from
// parent
maybeDetached.remove(childConnectorId);
}
}
Profiler.leave("updateConnectorHierarchy find new connectors");
// TODO This check should be done on the server side in
// the future so the hierarchy update is only sent when
// something actually has changed
List<ServerConnector> oldChildren = parentConnector
.getChildren();
boolean actuallyChanged = !Util.collectionsEquals(
oldChildren, newChildren);
if (!actuallyChanged) {
continue;
}
Profiler.enter("updateConnectorHierarchy handle HasComponentsConnector");
if (parentConnector instanceof HasComponentsConnector) {
HasComponentsConnector ccc = (HasComponentsConnector) parentConnector;
List<ComponentConnector> oldComponents = ccc
.getChildComponents();
if (!Util.collectionsEquals(oldComponents,
newComponents)) {
// Fire change event if the hierarchy has
// changed
ConnectorHierarchyChangeEvent event = GWT
.create(ConnectorHierarchyChangeEvent.class);
event.setOldChildren(oldComponents);
event.setConnector(parentConnector);
ccc.setChildComponents(newComponents);
result.events.add(event);
}
} else if (!newComponents.isEmpty()) {
VConsole.error("Hierachy claims "
+ Util.getConnectorString(parentConnector)
+ " has component children even though it isn't a HasComponentsConnector");
}
Profiler.leave("updateConnectorHierarchy handle HasComponentsConnector");
Profiler.enter("updateConnectorHierarchy setChildren");
parentConnector.setChildren(newChildren);
Profiler.leave("updateConnectorHierarchy setChildren");
Profiler.enter("updateConnectorHierarchy find removed children");
/*
* Find children removed from this parent and mark for
* removal unless they are already attached to some
* other parent.
*/
for (ServerConnector oldChild : oldChildren) {
if (oldChild.getParent() != parentConnector) {
// Ignore if moved to some other connector
continue;
}
if (!newChildren.contains(oldChild)) {
/*
* Consider child detached for now, will be
* cleared if it is later on added to some other
* parent.
*/
maybeDetached.add(oldChild.getConnectorId());
}
}
Profiler.leave("updateConnectorHierarchy find removed children");
} catch (final Throwable e) {
VConsole.error(e);
} finally {
Profiler.leave("updateConnectorHierarchy hierarchy entry");
}
}
Profiler.enter("updateConnectorHierarchy detach removed connectors");
/*
* Connector is in maybeDetached at this point if it has been
* removed from its parent but not added to any other parent
*/
JsArrayString maybeDetachedArray = maybeDetached.dump();
for (int i = 0; i < maybeDetachedArray.length(); i++) {
ServerConnector removed = connectorMap
.getConnector(maybeDetachedArray.get(i));
recursivelyDetach(removed, result.events);
}
Profiler.leave("updateConnectorHierarchy detach removed connectors");
Profiler.leave("updateConnectorHierarchy");
return result;
}
private void recursivelyDetach(ServerConnector connector,
JsArrayObject<ConnectorHierarchyChangeEvent> events) {
/*
* Reset state in an attempt to keep it consistent with the
* hierarchy. No children and no parent is the initial situation
* for the hierarchy, so changing the state to its initial value
* is the closest we can get without data from the server.
* #10151
*/
Profiler.enter("ApplicationConnection recursivelyDetach reset state");
try {
Profiler.enter("ApplicationConnection recursivelyDetach reset state - getStateType");
Type stateType = AbstractConnector.getStateType(connector);
Profiler.leave("ApplicationConnection recursivelyDetach reset state - getStateType");
// Empty state instance to get default property values from
Profiler.enter("ApplicationConnection recursivelyDetach reset state - createInstance");
Object defaultState = stateType.createInstance();
Profiler.leave("ApplicationConnection recursivelyDetach reset state - createInstance");
if (connector instanceof AbstractConnector) {
// optimization as the loop setting properties is very
// slow, especially on IE8
replaceState((AbstractConnector) connector,
defaultState);
} else {
SharedState state = connector.getState();
Profiler.enter("ApplicationConnection recursivelyDetach reset state - properties");
JsArrayObject<Property> properties = stateType
.getPropertiesAsArray();
int size = properties.size();