public void removeOldData(EventBean[] oldData, NamedWindowIndexRepository indexRepository) {
    for (int i = 0; i < oldData.length; i++) {
      RevisionEventBeanDeclared event = (RevisionEventBeanDeclared) oldData[i];

      // If the remove event is the latest event, remove from all caches
      if (event.isLatest()) {
        MultiKeyUntyped key = event.getKey();
        statePerKey.remove(key);

        for (EventTable table : indexRepository.getTables()) {
          table.remove(oldData);
        }
      }
    }
  }
  public void onUpdate(
      EventBean[] newData,
      EventBean[] oldData,
      NamedWindowRootView namedWindowRootView,
      NamedWindowIndexRepository indexRepository) {
    // If new data is filled, it is not a delete
    if ((newData == null) || (newData.length == 0)) {
      // we are removing an event
      RevisionEventBeanDeclared revisionEvent = (RevisionEventBeanDeclared) oldData[0];
      MultiKeyUntyped key = revisionEvent.getKey();
      statePerKey.remove(key);

      // Insert into indexes for fast deletion, if there are any
      for (EventTable table : indexRepository.getTables()) {
        table.remove(oldData);
      }

      // make as not the latest event since its due for removal
      revisionEvent.setLatest(false);

      namedWindowRootView.updateChildren(null, oldData);
      return;
    }

    RevisionEventBeanDeclared revisionEvent = (RevisionEventBeanDeclared) newData[0];
    EventBean underlyingEvent = revisionEvent.getUnderlyingFullOrDelta();
    EventType underyingEventType = underlyingEvent.getEventType();

    // obtain key values
    MultiKeyUntyped key = null;
    RevisionTypeDesc typesDesc = null;
    boolean isBaseEventType = false;
    if (underyingEventType == baseEventType) {
      key = PropertyUtility.getKeys(underlyingEvent, fullKeyGetters);
      isBaseEventType = true;
    } else {
      typesDesc = typeDescriptors.get(underyingEventType);

      // if this type cannot be found, check all supertypes, if any
      if (typesDesc == null) {
        Iterator<EventType> superTypes = underyingEventType.getDeepSuperTypes();
        if (superTypes != null) {
          EventType superType;
          for (; superTypes.hasNext(); ) {
            superType = superTypes.next();
            if (superType == baseEventType) {
              key = PropertyUtility.getKeys(underlyingEvent, fullKeyGetters);
              isBaseEventType = true;
              break;
            }
            typesDesc = typeDescriptors.get(superType);
            if (typesDesc != null) {
              typeDescriptors.put(underyingEventType, typesDesc);
              key = PropertyUtility.getKeys(underlyingEvent, typesDesc.getKeyPropertyGetters());
              break;
            }
          }
        }
      } else {
        key = PropertyUtility.getKeys(underlyingEvent, typesDesc.getKeyPropertyGetters());
      }

      if (key == null) {
        log.warn(
            "Ignoring event of event type '"
                + underyingEventType
                + "' for revision processing type '"
                + revisionEventTypeName);
        return;
      }
    }

    // get the state for this key value
    RevisionStateDeclared revisionState = statePerKey.get(key);

    // Delta event and no full
    if ((!isBaseEventType) && (revisionState == null)) {
      return; // Ignore the event, its a delta and we don't currently have a full event for it
    }

    // New full event
    if (revisionState == null) {
      revisionState = new RevisionStateDeclared(underlyingEvent, null, null);
      statePerKey.put(key, revisionState);

      // prepare revison event
      revisionEvent.setLastBaseEvent(underlyingEvent);
      revisionEvent.setKey(key);
      revisionEvent.setHolders(null);
      revisionEvent.setLatest(true);

      // Insert into indexes for fast deletion, if there are any
      for (EventTable table : indexRepository.getTables()) {
        table.add(newData);
      }

      // post to data window
      revisionState.setLastEvent(revisionEvent);
      namedWindowRootView.updateChildren(new EventBean[] {revisionEvent}, null);
      return;
    }

    // new version
    long versionNumber = revisionState.incRevisionNumber();

    // Previously-seen full event
    if (isBaseEventType) {
      revisionState.setHolders(null);
      revisionState.setBaseEventUnderlying(underlyingEvent);
    }
    // Delta event to existing full event
    else {
      int groupNum = typesDesc.getGroup().getGroupNum();
      RevisionBeanHolder[] holders = revisionState.getHolders();
      if (holders
          == null) // optimization - the full event sets it to null, deltas all get a new one
      {
        holders = new RevisionBeanHolder[groups.length];
      } else {
        holders = arrayCopy(holders); // preserve the last revisions
      }

      // add the new revision for a property group on top
      holders[groupNum] =
          new RevisionBeanHolder(
              versionNumber, underlyingEvent, typesDesc.getChangesetPropertyGetters());
      revisionState.setHolders(holders);
    }

    // prepare revision event
    revisionEvent.setLastBaseEvent(revisionState.getBaseEventUnderlying());
    revisionEvent.setHolders(revisionState.getHolders());
    revisionEvent.setKey(key);
    revisionEvent.setLatest(true);

    // get prior event
    RevisionEventBeanDeclared lastEvent = revisionState.getLastEvent();
    lastEvent.setLatest(false);

    // data to post
    EventBean[] newDataPost = new EventBean[] {revisionEvent};
    EventBean[] oldDataPost = new EventBean[] {lastEvent};

    // update indexes
    for (EventTable table : indexRepository.getTables()) {
      table.remove(oldDataPost);
      table.add(newDataPost);
    }

    // keep reference to last event
    revisionState.setLastEvent(revisionEvent);

    namedWindowRootView.updateChildren(newDataPost, oldDataPost);
  }