/**
   * The given name has been modified or removed in this context. Invalidate all local value
   * computations and listeners that depend on this name.
   */
  public void invalidate(String name, int eventType, Object oldValue, Set<Scheduled> scheduled) {
    ContextChangeEvent event = new ContextChangeEvent(this, eventType, null, name, oldValue);
    ValueComputation computation = localValueComputations.get(name);
    if (computation != null) {
      if (computation.shouldRemove(event)) {
        localValueComputations.remove(name);
        Collection<HashSet<Computation>> allListeners = listeners.values();
        for (HashSet<Computation> group : allListeners) {
          group.remove(computation);
        }
      }
      computation.handleInvalid(event, scheduled);
    }
    HashSet<Computation> namedComputations = listeners.get(name);
    if (namedComputations != null) {
      for (Computation listener : namedComputations) {
        listener.handleInvalid(event, scheduled);
      }
    }

    // invalidate this name in child contexts
    for (EclipseContext childContext : getChildren()) {
      childContext.invalidate(name, eventType, oldValue, scheduled);
    }
  }
  private void handleReparent(EclipseContext newParent, Set<Scheduled> scheduled) {
    // TBD should we lock waiting list while doing reparent?
    // Add "boolean inReparent" on the root context and process right away?
    processWaiting();
    // 1) everybody who depends on me: I need to collect combined list of names injected
    Set<String> usedNames = new HashSet<String>();
    collectDependentNames(usedNames);

    // 2) for each used name:
    for (Iterator<String> i = usedNames.iterator(); i.hasNext(); ) {
      String name = i.next();
      if (localValues.containsKey(name)) continue; // it is a local value
      Object oldValue = get(name);
      Object newValue = (newParent != null) ? newParent.get(name) : null;
      if (oldValue != newValue) invalidate(name, ContextChangeEvent.ADDED, oldValue, scheduled);
    }

    ContextChangeEvent event =
        new ContextChangeEvent(this, ContextChangeEvent.ADDED, null, null, null);
    for (Computation computation : localValueComputations.values()) {
      Collection<HashSet<Computation>> allListeners = listeners.values();
      for (HashSet<Computation> group : allListeners) {
        group.remove(computation);
      }
      computation.handleInvalid(event, scheduled);
    }
    localValueComputations.clear();
  }
  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.e4.core.services.context.IEclipseContext#dispose()
   */
  public void dispose() {
    // dispose of child contexts first
    for (EclipseContext childContext : getChildren()) {
      childContext.dispose();
    }

    ContextChangeEvent event =
        new ContextChangeEvent(this, ContextChangeEvent.DISPOSE, null, null, null);
    Set<Scheduled> scheduled = new LinkedHashSet<Scheduled>();
    Set<Computation> allComputations = getListeners();
    listeners.clear();
    allComputations.addAll(activeRATs);
    activeRATs.clear();
    for (Computation computation : allComputations) {
      computation.handleInvalid(event, scheduled);
    }
    processScheduled(scheduled);

    synchronized (notifyOnDisposal) {
      for (IContextDisposalListener listener : notifyOnDisposal) {
        listener.disposed(this);
      }
    }

    localValueComputations.clear();

    // if this was the parent's active child, deactivate it
    EclipseContext parent = getParent();
    if (parent != null) {
      if (this == parent.getActiveChild()) parent.set(ACTIVE_CHILD, null);
    }

    localValues.clear();

    if (parent != null) parent.removeChild(this);

    if (debugAddOn != null)
      debugAddOn.notify(this, IEclipseContextDebugger.EventType.DISPOSED, null);
  }