/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "exception.h" #include "hdfs.h" #include "jni_helper.h" #include #include #include #include #define EXCEPTION_INFO_LEN (sizeof(gExceptionInfo)/sizeof(gExceptionInfo[0])) struct ExceptionInfo { const char * const name; int noPrintFlag; int excErrno; }; static const struct ExceptionInfo gExceptionInfo[] = { { .name = "java.io.FileNotFoundException", .noPrintFlag = NOPRINT_EXC_FILE_NOT_FOUND, .excErrno = ENOENT, }, { .name = "org.apache.hadoop.security.AccessControlException", .noPrintFlag = NOPRINT_EXC_ACCESS_CONTROL, .excErrno = EACCES, }, { .name = "org.apache.hadoop.fs.UnresolvedLinkException", .noPrintFlag = NOPRINT_EXC_UNRESOLVED_LINK, .excErrno = ENOLINK, }, { .name = "org.apache.hadoop.fs.ParentNotDirectoryException", .noPrintFlag = NOPRINT_EXC_PARENT_NOT_DIRECTORY, .excErrno = ENOTDIR, }, { .name = "java.lang.IllegalArgumentException", .noPrintFlag = NOPRINT_EXC_ILLEGAL_ARGUMENT, .excErrno = EINVAL, }, { .name = "java.lang.OutOfMemoryError", .noPrintFlag = 0, .excErrno = ENOMEM, }, { .name = "org.apache.hadoop.hdfs.server.namenode.SafeModeException", .noPrintFlag = 0, .excErrno = EROFS, }, { .name = "org.apache.hadoop.fs.FileAlreadyExistsException", .noPrintFlag = 0, .excErrno = EEXIST, }, { .name = "org.apache.hadoop.hdfs.protocol.QuotaExceededException", .noPrintFlag = 0, .excErrno = EDQUOT, }, { .name = "org.apache.hadoop.hdfs.server.namenode.LeaseExpiredException", .noPrintFlag = 0, .excErrno = ESTALE, }, }; void getExceptionInfo(const char *excName, int noPrintFlags, int *excErrno, int *shouldPrint) { int i; for (i = 0; i < EXCEPTION_INFO_LEN; i++) { if (strstr(gExceptionInfo[i].name, excName)) { break; } } if (i < EXCEPTION_INFO_LEN) { *shouldPrint = !(gExceptionInfo[i].noPrintFlag & noPrintFlags); *excErrno = gExceptionInfo[i].excErrno; } else { *shouldPrint = 1; *excErrno = EINTERNAL; } } int printExceptionAndFreeV(JNIEnv *env, jthrowable exc, int noPrintFlags, const char *fmt, va_list ap) { int i, noPrint, excErrno; char *className = NULL; jstring jStr = NULL; jvalue jVal; jthrowable jthr; jthr = classNameOfObject(exc, env, &className); if (jthr) { fprintf(stderr, "PrintExceptionAndFree: error determining class name " "of exception.\n"); className = strdup("(unknown)"); destroyLocalReference(env, jthr); } for (i = 0; i < EXCEPTION_INFO_LEN; i++) { if (!strcmp(gExceptionInfo[i].name, className)) { break; } } if (i < EXCEPTION_INFO_LEN) { noPrint = (gExceptionInfo[i].noPrintFlag & noPrintFlags); excErrno = gExceptionInfo[i].excErrno; } else { noPrint = 0; excErrno = EINTERNAL; } if (!noPrint) { vfprintf(stderr, fmt, ap); fprintf(stderr, " error:\n"); // We don't want to use ExceptionDescribe here, because that requires a // pending exception. Instead, use ExceptionUtils. jthr = invokeMethod(env, &jVal, STATIC, NULL, "org/apache/commons/lang/exception/ExceptionUtils", "getStackTrace", "(Ljava/lang/Throwable;)Ljava/lang/String;", exc); if (jthr) { fprintf(stderr, "(unable to get stack trace for %s exception: " "ExceptionUtils::getStackTrace error.)\n", className); destroyLocalReference(env, jthr); } else { jStr = jVal.l; const char *stackTrace = (*env)->GetStringUTFChars(env, jStr, NULL); if (!stackTrace) { fprintf(stderr, "(unable to get stack trace for %s exception: " "GetStringUTFChars error.)\n", className); } else { fprintf(stderr, "%s", stackTrace); (*env)->ReleaseStringUTFChars(env, jStr, stackTrace); } } } destroyLocalReference(env, jStr); destroyLocalReference(env, exc); free(className); return excErrno; } int printExceptionAndFree(JNIEnv *env, jthrowable exc, int noPrintFlags, const char *fmt, ...) { va_list ap; int ret; va_start(ap, fmt); ret = printExceptionAndFreeV(env, exc, noPrintFlags, fmt, ap); va_end(ap); return ret; } int printPendingExceptionAndFree(JNIEnv *env, int noPrintFlags, const char *fmt, ...) { va_list ap; int ret; jthrowable exc; exc = (*env)->ExceptionOccurred(env); if (!exc) { va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, " error: (no exception)"); ret = 0; } else { (*env)->ExceptionClear(env); va_start(ap, fmt); ret = printExceptionAndFreeV(env, exc, noPrintFlags, fmt, ap); va_end(ap); } return ret; } jthrowable getPendingExceptionAndClear(JNIEnv *env) { jthrowable jthr = (*env)->ExceptionOccurred(env); if (!jthr) return NULL; (*env)->ExceptionClear(env); return jthr; } jthrowable newRuntimeError(JNIEnv *env, const char *fmt, ...) { char buf[512]; jobject out, exc; jstring jstr; va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); jstr = (*env)->NewStringUTF(env, buf); if (!jstr) { // We got an out of memory exception rather than a RuntimeException. // Too bad... return getPendingExceptionAndClear(env); } exc = constructNewObjectOfClass(env, &out, "RuntimeException", "(java/lang/String;)V", jstr); (*env)->DeleteLocalRef(env, jstr); // Again, we'll either get an out of memory exception or the // RuntimeException we wanted. return (exc) ? exc : out; }