private void handleAddNotification(NotificationInfo n) {

    // validation for ADD reference
    if (n.isReferenceNotification()) {

      // non model element references must be marked transient
      if (!(n.getNewValue() instanceof EObject)) {
        n.setValid(false);
        n.setValidationMessage(
            "Non-transient non-EObject reference feature detected: "
                + n.getNotifier().getClass().getCanonicalName()
                + "-"
                + n.getReference().getName());
        return;
      }

      // checking up on EMF...
      if (!n.getReference().isMany()) {
        n.setValid(false);
        n.setValidationMessage(
            "Unkown notification state: ADD notification on reference "
                + "feature with isMany==false");
      }
    }

    // no validation for ADD attribute

  }
  private void handleAddManyNotification(NotificationInfo n) {

    // TODO add validation
    // // attributes not allowed for ADD_MANY (yet)
    // if (n.isAttributeNotification()) {
    // n.setValid(false);
    // n.setValidationMessage("ADD_MANY on attribute feature with multiplicity greater than 1 not
    // yet supported.");
    // return;
    // }

    // reference validation
    if (n.isReferenceNotification()) {

      // the new guys must come in a list
      if (!(n.getNewValue() instanceof List<?>)) {
        n.setValid(false);
        n.setValidationMessage(
            "Non-List newValue argument for ADD_MANY notification on: "
                + n.getNotifier().getClass().getCanonicalName()
                + "-"
                + n.getReference().getName());
        return;
      }

      // checking up on EMF, the reference must have max multiplicity greater than 1...
      if (!n.getReference().isMany()) {
        n.setValid(false);
        n.setValidationMessage(
            "Unkown notification state: ADD_MANY notification on reference "
                + "feature with isMany==false");
        return;
      }
    }
  }
  private void handleSetNotification(NotificationInfo n) {

    // validation for SET reference

    if (n.isReferenceNotification()) {

      // sanity check newValue and oldValue must be ModelElements or null
      Object newValueObject = n.getNewValue();
      Object oldValueObject = n.getOldValue();

      boolean newValIsNoME = newValueObject != null && !(newValueObject instanceof EObject);
      boolean oldValIsNoME = oldValueObject != null && !(oldValueObject instanceof EObject);
      if (newValIsNoME || oldValIsNoME) {
        // non model element references must be marked transient
        n.setValid(false);
        n.setValidationMessage(
            "Non-transient non-EObject reference feature detected: "
                + n.getNotifier().getClass().getCanonicalName()
                + "-"
                + n.getReference().getName());
        return;
      }
    }

    // no validation for SET attribute
  }
  private void handleMoveNotification(NotificationInfo n) {

    // if (n.isAttributeNotification()) {
    // n.setValid(false);
    // n.setValidationMessage("MOVE notification on attribute feature with multiplicty"
    // + "greater 1 not supported yet!");
    // return;
    // }

    if (n.isReferenceNotification()) {
      // sanity checks
      if (n.getNewValue() == null || n.getOldValue() == null) {
        n.setValid(false);
        n.setValidationMessage(
            "Null detected in oldValue or NewValue of move notification about: "
                + n.getNotifier().getClass().getCanonicalName()
                + "-"
                + n.getReference().getName());
        return;
      }

      if (!(n.getNewValue() instanceof EObject)) {
        // non model element references must be marked transient

        n.setValid(false);
        n.setValidationMessage(
            "Non-transient non-EObject reference feature detected: "
                + n.getNotifier().getClass().getCanonicalName()
                + "-"
                + n.getReference().getName());
        return;
      }

      if (!(n.getOldValue() instanceof Integer)) {
        n.setValid(false);
        n.setValidationMessage("Error with old position in move: not an Integer");
        return;
      }
    }
  }
  /**
   * Validates a notification and sets its valid flag and validationmessage string.
   *
   * @param n the notification to validate
   * @return
   */
  protected void validate(NotificationInfo n) {

    if (n == null) {
      throw new IllegalArgumentException("NotificationInfo argument cannot be null");
    }

    // assume notification is valid, handlers will reset state and message, if something is wrong
    n.setValid(true);
    n.setValidationMessage("OK");

    // consider touch and transient notification to always be valid
    if (n.isTouch() || n.isTransient()) {
      return;
    }

    switch (n.getEventType()) {
      case Notification.SET:
        handleSetNotification(n);
        break;
      case Notification.ADD:
        handleAddNotification(n);
        break;
      case Notification.REMOVE:
        handleRemoveNotification(n);
        break;
      case Notification.ADD_MANY:
        handleAddManyNotification(n);
        break;
      case Notification.REMOVE_MANY:
        handleRemoveManyNotification(n);
        break;
      case Notification.UNSET:
        handleUnsetNotification(n);
        break;
      case Notification.MOVE:
        handleMoveNotification(n);
        break;
      default:
        handleUnknownNotification(n);
        break;
    }
  }
 private void handleUnknownNotification(NotificationInfo n) {
   n.setValid(false);
   n.setValidationMessage("Error: unknown notification event type. " + n.toString());
 }
 private void handleUnsetNotification(NotificationInfo n) {
   n.setValid(false);
   n.setValidationMessage("Cannot handle UNSET notifications");
 }