//
  // Initialize the hashtable of methods which are allowed to raise
  // SQLFeatureNotSupportedException.
  //
  private void initializeExcludableMap(HashSet<String> vanishedMethodList) throws Exception {
    excludableMap = new Hashtable<Class, HashSet<Method>>();

    int count = rawExcludables.length;

    for (int i = 0; i < count; i++) {
      Exclusions exclusions = rawExcludables[i];
      Class<?> iface = exclusions.getInterface();
      MD[] mds = exclusions.getExcludedMethods();
      int exclusionCount = mds.length;
      HashSet<Method> excludedMethodSet = new HashSet<Method>();

      for (int j = 0; j < exclusionCount; j++) {
        MD md = mds[j];

        if (!md.requiredAtThisLevel()) {
          continue;
        }

        //
        // If we are strictly enforcing the JDBC standard,
        // then expose the mandatory methods which we know Derby
        // doesn't implement.
        //
        if (STRICT_ENFORCEMENT && !md.isOptional()) {
          continue;
        }

        Method method = null;

        try {
          method = iface.getMethod(md.getMethodName(), md.getArgTypes());
        } catch (NoSuchMethodException e) {
        }

        if (method == null) {
          vanishedMethodList.add(
              "Method has vanished from SQL interface: " + iface.getName() + "." + md);
        }

        excludedMethodSet.add(method);
      }

      excludableMap.put(iface, excludedMethodSet);
    }
  }
 //
 // Record an unexpected error.
 //
 private void recordUnexpectedError(
     Object candidate,
     Class iface,
     Method method,
     HashSet<String> notUnderstoodList,
     Throwable cause)
     throws Exception {
   notUnderstoodList.add(candidate.getClass().getName() + " " + method + " raises " + cause);
 }
  //
  // Examine a single method to see if it raises SQLFeatureNotSupportedException.
  //
  private void vetMethod(
      Object candidate,
      Class iface,
      Method method,
      HashSet<String> unsupportedList,
      HashSet<String> notUnderstoodList)
      throws Exception {
    try {
      method.invoke(candidate, getNullArguments(method.getParameterTypes()));

      // it's ok for the method to succeed
    } catch (Throwable e) {
      if (!(e instanceof InvocationTargetException)) {
        recordUnexpectedError(candidate, iface, method, notUnderstoodList, e);
      } else {
        Throwable cause = e.getCause();

        if (cause instanceof SQLFeatureNotSupportedException) {
          boolean isExcludable = isExcludable(method);

          if (!isExcludable) {
            StackTraceElement[] stack = cause.getStackTrace();
            int i = 0;
            while (i < stack.length && !stack[i].getMethodName().equals("notImplemented")) {
              ++i;
            }
            while (i < stack.length && stack[i].getMethodName().equals("notImplemented")) {
              ++i;
            }
            if (i == stack.length) {
              // cause.printStackTrace();
            }

            unsupportedList.add(
                candidate.getClass().getName()
                    + ": "
                    + method
                    + "@"
                    + (i == stack.length ? "no source" : cause.getStackTrace()[i]));
          } else {

          }
        } else if (cause instanceof SQLException) {
          // swallow other SQLExceptions, caused by bogus args
        } else if (cause instanceof NullPointerException) {
          // swallow other NPEs, caused by bogus args
        } else if (cause instanceof ArrayIndexOutOfBoundsException) {
          // swallow these, caused by bogus args
        } else {
          recordUnexpectedError(candidate, iface, method, notUnderstoodList, cause);
        }
      }
    }
  }