/** * Register the given connector. * * <p>The lookup method {@link #getConnector(String)} only returns registered connectors. * * @param connector The connector to register. */ public void registerConnector(ClientConnector connector) { boolean wasUnregistered = unregisteredConnectors.remove(connector); String connectorId = connector.getConnectorId(); ClientConnector previouslyRegistered = connectorIdToConnector.get(connectorId); if (previouslyRegistered == null) { connectorIdToConnector.put(connectorId, connector); uninitializedConnectors.add(connector); if (getLogger().isLoggable(Level.FINE)) { getLogger() .log( Level.FINE, "Registered {0} ({1})", new Object[] {connector.getClass().getSimpleName(), connectorId}); } } else if (previouslyRegistered != connector) { throw new RuntimeException("A connector with id " + connectorId + " is already registered!"); } else if (!wasUnregistered) { getLogger() .log( Level.WARNING, "An already registered connector was registered again: {0} ({1})", new Object[] {connector.getClass().getSimpleName(), connectorId}); } dirtyConnectors.add(connector); }
/** * Returns {@link #getConnectorString(ClientConnector)} for the connector and its parent (if it * has a parent). * * @param connector The connector * @return A string describing the connector and its parent */ private String getConnectorAndParentInfo(ClientConnector connector) { String message = getConnectorString(connector); if (connector.getParent() != null) { message += " (parent: " + getConnectorString(connector.getParent()) + ")"; } return message; }
/** * Cleans the connector map from all connectors that are no longer attached to the application. * This should only be called by the framework. */ public void cleanConnectorMap() { if (!unregisteredConnectors.isEmpty()) { removeUnregisteredConnectors(); } // 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<ClientConnector> iterator = connectorIdToConnector.values().iterator(); GlobalResourceHandler globalResourceHandler = uI.getSession().getGlobalResourceHandler(false); while (iterator.hasNext()) { ClientConnector connector = iterator.next(); assert connector != null; if (connector.getUI() != uI) { // If connector is no longer part of this uI, // remove it from the map. If it is re-attached to the // application at some point it will be re-added through // registerConnector(connector) // This code should never be called as cleanup should take place // in detach() getLogger() .log( Level.WARNING, "cleanConnectorMap unregistered connector {0}. This should have been done when the connector was detached.", getConnectorAndParentInfo(connector)); if (globalResourceHandler != null) { globalResourceHandler.unregisterConnector(connector); } uninitializedConnectors.remove(connector); diffStates.remove(connector); iterator.remove(); } else if (!uninitializedConnectors.contains(connector) && !LegacyCommunicationManager.isConnectorVisibleToClient(connector)) { uninitializedConnectors.add(connector); diffStates.remove(connector); if (getLogger().isLoggable(Level.FINE)) { getLogger() .log( Level.FINE, "cleanConnectorMap removed state for {0} as it is not visible", getConnectorAndParentInfo(connector)); } } } cleanStreamVariables(); }
/** * Returns a string with the connector name and id. Useful mostly for debugging and logging. * * @param connector The connector * @return A string that describes the connector */ private String getConnectorString(ClientConnector connector) { if (connector == null) { return "(null)"; } String connectorId; try { connectorId = connector.getConnectorId(); } catch (RuntimeException e) { // This happens if the connector is not attached to the application. // SHOULD not happen in this case but theoretically can. connectorId = "@" + Integer.toHexString(connector.hashCode()); } return connector.getClass().getName() + "(" + connectorId + ")"; }
private void removeUnregisteredConnectors() { GlobalResourceHandler globalResourceHandler = uI.getSession().getGlobalResourceHandler(false); for (ClientConnector connector : unregisteredConnectors) { ClientConnector removedConnector = connectorIdToConnector.remove(connector.getConnectorId()); assert removedConnector == connector; if (globalResourceHandler != null) { globalResourceHandler.unregisterConnector(connector); } uninitializedConnectors.remove(connector); diffStates.remove(connector); } unregisteredConnectors.clear(); }
private boolean isHierarchyComplete() { boolean noErrors = true; Set<ClientConnector> danglingConnectors = new HashSet<ClientConnector>(connectorIdToConnector.values()); LinkedList<ClientConnector> stack = new LinkedList<ClientConnector>(); stack.add(uI); while (!stack.isEmpty()) { ClientConnector connector = stack.pop(); danglingConnectors.remove(connector); Iterable<ClientConnector> 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; }
/** * Unregister the given connector. * * <p>The lookup method {@link #getConnector(String)} only returns registered connectors. * * @param connector The connector to unregister */ public void unregisterConnector(ClientConnector connector) { String connectorId = connector.getConnectorId(); if (!connectorIdToConnector.containsKey(connectorId)) { getLogger() .log( Level.WARNING, "Tried to unregister {0} ({1}) which is not registered", new Object[] {connector.getClass().getSimpleName(), connectorId}); return; } if (connectorIdToConnector.get(connectorId) != connector) { throw new RuntimeException( "The given connector with id " + connectorId + " is not the one that was registered for that id"); } Set<String> unregisteredConnectorIds = syncIdToUnregisteredConnectorIds.get(currentSyncId); if (unregisteredConnectorIds == null) { unregisteredConnectorIds = new HashSet<String>(); syncIdToUnregisteredConnectorIds.put(currentSyncId, unregisteredConnectorIds); } unregisteredConnectorIds.add(connectorId); dirtyConnectors.remove(connector); if (unregisteredConnectors.add(connector)) { if (getLogger().isLoggable(Level.FINE)) { getLogger() .log( Level.FINE, "Unregistered {0} ({1})", new Object[] {connector.getClass().getSimpleName(), connectorId}); } } else { getLogger() .log( Level.WARNING, "Unregistered {0} ({1}) that was already unregistered.", new Object[] {connector.getClass().getSimpleName(), connectorId}); } }
public void setDiffState(ClientConnector connector, JSONObject diffState) { assert getConnector(connector.getConnectorId()) == connector; diffStates.put(connector, diffState); }
public JSONObject getDiffState(ClientConnector connector) { assert getConnector(connector.getConnectorId()) == connector; return diffStates.get(connector); }
/** * Checks whether the given connector has already been initialized in the browser. The given * connector should be registered with this connector tracker. * * @param connector the client connector to check * @return <code>true</code> if the initial state has previously been sent to the browser, <code> * false</code> if the client-side doesn't already know anything about the connector. */ public boolean isClientSideInitialized(ClientConnector connector) { assert connectorIdToConnector.get(connector.getConnectorId()) == connector : "Connector should be registered with this ConnectorTracker"; return !uninitializedConnectors.contains(connector); }