/**
   * Do a recursive find and replace of objects pointed to by this object.
   *
   * @since v1.0
   * @param objectText is the canonical string representation of the object that we want to replace.
   * @param replacement is the object that we want to replace it with.
   * @param matchSubstring a boolean which tells if we should match a substring of the target object
   *     A replacement will occur if a portion of the structure is found with matching encoded text
   *     (a substring if matchSubstring is true) as objectText and with the same class as
   *     replacement.
   */
  public void replace(String objectText, GenericObject replacement, boolean matchSubstring)
      throws IllegalArgumentException {
    if (objectText == null || replacement == null) {
      throw new IllegalArgumentException("null argument!");
    }
    Class replacementClass = replacement.getClass();
    Class myclass = getClass();
    Field[] fields = myclass.getDeclaredFields();
    for (int i = 0; i < fields.length; i++) {
      Field f = fields[i];
      Class fieldType = f.getType();
      if (!getClassFromName(SIP_PACKAGE + ".GenericObject").isAssignableFrom(fieldType)
          && !getClassFromName(SIP_PACKAGE + ".GenericObjectList").isAssignableFrom(fieldType)) {
        continue;
      } else if ((f.getModifiers() & Modifier.PRIVATE) == Modifier.PRIVATE) {
        continue;
      }

      try {
        if (fieldType.equals(replacementClass)) {

          if (GenericObject.isMySubclass(replacementClass)) {
            GenericObject obj = (GenericObject) f.get(this);
            if (!matchSubstring) {
              if (objectText.compareTo(obj.encode()) == 0) {
                f.set(this, replacement);
              }
            } else {
              // Substring match is specified
              if (obj.encode().indexOf(objectText) >= 0) {
                f.set(this, replacement);
              }
            }
          }
        } else if (GenericObjectList.isMySubclass(replacementClass)) {
          GenericObjectList obj = (GenericObjectList) f.get(this);
          if (!matchSubstring) {
            if (objectText.compareTo(obj.encode()) == 0) {
              f.set(this, replacement);
            }
          } else {
            if (obj.encode().indexOf(objectText) >= 0) {
              f.set(this, replacement);
            }
          }
        } else if (getClassFromName(SIP_PACKAGE + ".GenericObject").isAssignableFrom(fieldType)) {
          GenericObject g = (GenericObject) f.get(this);
          g.replace(objectText, replacement, matchSubstring);
        } else if (getClassFromName(SIP_PACKAGE + ".GenericObjectList")
            .isAssignableFrom(fieldType)) {
          GenericObjectList g = (GenericObjectList) f.get(this);
          g.replace(objectText, replacement, matchSubstring);
        }
      } catch (IllegalAccessException ex) {
        InternalErrorHandler.handleException(ex);
      }
    }
  }