Fennel: /home/pub/open/dev/fennel/farrago/JniUtil.cpp Source File (original) (raw)

00001 00002 00003 00004 00005 00006 00007 00008 00009 00010 00011 00012 00013 00014 00015 00016 00017 00018 00019 00020 00021 00022 00023 00024 #include "fennel/common/CommonPreamble.h" 00025 #include "fennel/farrago/JniUtil.h" 00026 #include "fennel/farrago/JavaExcn.h" 00027 #include "fennel/common/FennelResource.h" 00028 #include "fennel/common/ConfigMap.h" 00029 #include "fennel/common/Backtrace.h" 00030 #include "fennel/tuple/StoredTypeDescriptor.h" 00031 00032 #ifdef MSVC 00033 #include <process.h> 00034 #endif 00035 00036 #ifndef MSVC 00037 #include <signal.h> 00038 #endif 00039 00040 FENNEL_BEGIN_CPPFILE("$Id: //open/dev/fennel/farrago/JniUtil.cpp#35 $"); 00041 00042 ParamName JniUtilParams::paramJniHandleTraceFile = "jniHandleTraceFile"; 00043 00044 JavaVM *JniUtil::pVm = NULL; 00045 jmethodID JniUtil::methGetClassName = 0; 00046 jmethodID JniUtil::methGetInterfaces = 0; 00047 jmethodID JniUtil::methGetModifiers = 0; 00048 jclass JniUtil::classModifier = 0; 00049 jmethodID JniUtil::methIsPublic = 0; 00050 jmethodID JniUtil::methHasNext = 0; 00051 jmethodID JniUtil::methNext = 0; 00052 jmethodID JniUtil::methIterator = 0; 00053 jmethodID JniUtil::methGetJavaStreamHandle = 0; 00054 jmethodID JniUtil::methGetIndexRoot = 0; 00055 jmethodID JniUtil::methToString = 0; 00056 jclass JniUtil::classRhBase64; 00057 jmethodID JniUtil::methRandomUUID; 00058 jclass JniUtil::classUUID; 00059 jmethodID JniUtil::methFarragoTransformInit = 0; 00060 jmethodID JniUtil::methFarragoTransformExecute = 0; 00061 jmethodID JniUtil::methFarragoTransformSetInputFetchTimeout = 0; 00062 jmethodID JniUtil::methFarragoTransformRestart = 0; 00063 jclass JniUtil::classFarragoTransformInputBinding = 0; 00064 jmethodID JniUtil::methFarragoTransformInputBindingCons = 0; 00065 jmethodID JniUtil::methFarragoRuntimeContextStatementClassForName = 0; 00066 jmethodID JniUtil::methFarragoRuntimeContextFindFarragoTransform = 0; 00067 jclass JniUtil::classLong; 00068 jclass JniUtil::classInteger; 00069 jclass JniUtil::classShort; 00070 jclass JniUtil::classDouble; 00071 jclass JniUtil::classFloat; 00072 jclass JniUtil::classBoolean; 00073 jmethodID JniUtil::methLongValueOf = 0; 00074 jmethodID JniUtil::methIntegerValueOf = 0; 00075 jmethodID JniUtil::methShortValueOf = 0; 00076 jmethodID JniUtil::methDoubleValueOf = 0; 00077 jmethodID JniUtil::methFloatValueOf = 0; 00078 jmethodID JniUtil::methBooleanValueOf = 0; 00079 jmethodID JniUtil::methLongValue = 0; 00080 jmethodID JniUtil::methIntValue = 0; 00081 jmethodID JniUtil::methShortValue = 0; 00082 jmethodID JniUtil::methDoubleValue = 0; 00083 jmethodID JniUtil::methFloatValue = 0; 00084 jmethodID JniUtil::methBooleanValue = 0; 00085 jmethodID JniUtil::methBase64Decode; 00086 jmethodID JniUtil::methUtilGetStackTrace; 00087 jclass JniUtil::classUtil; 00088 00089 AtomicCounter JniUtil::handleCount; 00090 00091 bool JniUtil::traceHandleCountEnabled = false; 00092 bool JniUtil::closeHandleCountTraceOnZero = false; 00093 std::ofstream JniUtil::handleCountTraceStream; 00094 00095 JavaThreadTracker JniUtil::threadTracker; 00096 00097 00098 #ifndef MSVC 00099 static void debugger_signalHandler(int signum) 00100 { 00101
00102 } 00103 #endif 00104 00105 JniUtilParams::JniUtilParams() 00106 { 00107 jniHandleTraceFile = ""; 00108 } 00109 00110 void JniUtilParams::readConfig(ConfigMap const &configMap) 00111 { 00112 jniHandleTraceFile = configMap.getStringParam(paramJniHandleTraceFile); 00113 } 00114 00115 void JniUtil::initDebug(char const *envVarName) 00116 { 00117 char *pDebug = getenv(envVarName); 00118 if (pDebug && (atoi(pDebug) >= 1)) { 00119 char pidstr[32]; 00120 snprintf(pidstr, 32, "%d", getpid()); 00121 std::cout << "Waiting for debugger; pid=" << pidstr << std::endl; 00122 std::cout.flush(); 00123 #ifdef __MSVC__ 00124
00125
00126 _sleep(600000); 00127 #else 00128
00129
00130
00131
00132
00133 if (atoi(pDebug) == 1) { 00134 sleep(60000); 00135 } else { 00136 struct sigaction act; 00137 struct sigaction oldact; 00138 00139 act.sa_handler = debugger_signalHandler; 00140 sigemptyset(&act.sa_mask); 00141 act.sa_flags = 0; 00142 00143 if (!sigaction(SIGHUP, &act, &oldact)) { 00144
00145 pause(); 00146 00147
00148 sigaction(SIGHUP, &oldact, NULL); 00149 } else { 00150
00151 sleep(60000); 00152 } 00153 } 00154 #endif 00155 } 00156 } 00157 00158 void JniUtil::configure(const JniUtilParams &params) 00159 { 00160
00161
00162
00163 if (handleCountTraceStream.is_open()) { 00164 assert(false); 00165 00166
00167 handleCountTraceStream 00168 << "ERROR: trace stream already open" << std::endl; 00169 handleCountTraceStream.flush(); 00170 handleCountTraceStream.close(); 00171 traceHandleCountEnabled = false; 00172 closeHandleCountTraceOnZero = false; 00173 } 00174 00175 if (params.jniHandleTraceFile.length() > 0) { 00176 handleCountTraceStream.open( 00177 params.jniHandleTraceFile.c_str(), std::ios::app); 00178 00179 handleCountTraceStream 00180 << "# Fennel JNI Handle Trace (see //open/util/bin/checkJniHandleTrace.pl)" 00181 << std::endl; 00182 00183 assert(handleCountTraceStream.good()); 00184 00185 traceHandleCountEnabled = true; 00186 closeHandleCountTraceOnZero = false; 00187 } 00188 } 00189 00190 void JniUtil::shutdown() 00191 { 00192
00193
00194 if (traceHandleCountEnabled) { 00195 closeHandleCountTraceOnZero = true; 00196 } 00197 } 00198 00199 00200 jint JniUtil::init(JavaVM *pVmInit) 00201 { 00202
00203
00204
00205
00206
00207 AutoBacktrace::install(false); 00208 pVm = pVmInit; 00209 JniEnvAutoRef pEnv; 00210 jclass classClass = pEnv->FindClass("java/lang/Class"); 00211 jclass classObject = pEnv->FindClass("java/lang/Object"); 00212 jclass classCollection = pEnv->FindClass("java/util/Collection"); 00213 jclass classIterator = pEnv->FindClass("java/util/Iterator"); 00214 00215
00216
00217
00218 classRhBase64 = pEnv->FindClass("org/eigenbase/util/RhBase64"); 00219 classRhBase64 = (jclass) pEnv->NewGlobalRef(classRhBase64); 00220 classUUID = pEnv->FindClass("java/util/UUID"); 00221 classUUID = (jclass) pEnv->NewGlobalRef(classUUID); 00222 00223 jclass classFennelJavaStreamMap = pEnv->FindClass( 00224 "net/sf/farrago/fennel/FennelJavaStreamMap"); 00225 jclass classFarragoTransform = pEnv->FindClass( 00226 "net/sf/farrago/runtime/FarragoTransform"); 00227 00228
00229 jclass tempInputBinding = 00230 pEnv->FindClass( 00231 "net/sf/farrago/runtime/FarragoTransform$InputBinding"); 00232 classFarragoTransformInputBinding = 00233 (jclass)pEnv->NewGlobalRef(tempInputBinding); 00234 00235 jclass classFarragoRuntimeContext = pEnv->FindClass( 00236 "net/sf/farrago/runtime/FarragoRuntimeContext"); 00237 methGetClassName = pEnv->GetMethodID( 00238 classClass,"getName","()Ljava/lang/String;"); 00239 methGetInterfaces = pEnv->GetMethodID( 00240 classClass,"getInterfaces","()[Ljava/lang/Class;"); 00241 methGetModifiers = pEnv->GetMethodID( 00242 classClass,"getModifiers","()I"); 00243 00244 jclass tempClassModifier = pEnv->FindClass("java/lang/reflect/Modifier"); 00245 classModifier = (jclass)pEnv->NewGlobalRef(tempClassModifier); 00246 methIsPublic = pEnv->GetStaticMethodID(classModifier, "isPublic", "(I)Z"); 00247 00248 methIterator = pEnv->GetMethodID( 00249 classCollection,"iterator","()Ljava/util/Iterator;"); 00250 methHasNext = pEnv->GetMethodID( 00251 classIterator,"hasNext","()Z"); 00252 methNext = pEnv->GetMethodID( 00253 classIterator,"next","()Ljava/lang/Object;"); 00254 methGetJavaStreamHandle = pEnv->GetMethodID( 00255 classFennelJavaStreamMap,"getJavaStreamHandle", 00256 "(I)J"); 00257 methGetIndexRoot = pEnv->GetMethodID( 00258 classFennelJavaStreamMap,"getIndexRoot", 00259 "(J)J"); 00260 methToString = pEnv->GetMethodID( 00261 classObject,"toString","()Ljava/lang/String;"); 00262 00263 jclass tempClassLong = pEnv->FindClass("java/lang/Long"); 00264 classLong = (jclass)pEnv->NewGlobalRef(tempClassLong); 00265 methLongValueOf = 00266 pEnv->GetStaticMethodID(classLong, "valueOf", "(J)Ljava/lang/Long;"); 00267 methLongValue = pEnv->GetMethodID(classLong, "longValue", "()J"); 00268 00269 jclass tempClassInteger = pEnv->FindClass("java/lang/Integer"); 00270 classInteger = (jclass)pEnv->NewGlobalRef(tempClassInteger); 00271 methIntegerValueOf = 00272 pEnv->GetStaticMethodID( 00273 classInteger, "valueOf", "(I)Ljava/lang/Integer;"); 00274 methIntValue = pEnv->GetMethodID(classInteger, "intValue", "()I"); 00275 00276 jclass tempClassShort = pEnv->FindClass("java/lang/Short"); 00277 classShort = (jclass)pEnv->NewGlobalRef(tempClassShort); 00278 methShortValueOf = 00279 pEnv->GetStaticMethodID(classShort, "valueOf", "(S)Ljava/lang/Short;"); 00280 methShortValue = pEnv->GetMethodID(classShort, "shortValue", "()S"); 00281 00282 jclass tempClassDouble = pEnv->FindClass("java/lang/Double"); 00283 classDouble = (jclass)pEnv->NewGlobalRef(tempClassDouble); 00284 methDoubleValueOf = 00285 pEnv->GetStaticMethodID( 00286 classDouble, "valueOf", "(D)Ljava/lang/Double;"); 00287 methDoubleValue = pEnv->GetMethodID(classDouble, "doubleValue", "()D"); 00288 00289 jclass tempClassFloat = pEnv->FindClass("java/lang/Float"); 00290 classFloat = (jclass)pEnv->NewGlobalRef(tempClassFloat); 00291 methFloatValueOf = 00292 pEnv->GetStaticMethodID(classFloat, "valueOf", "(F)Ljava/lang/Float;"); 00293 methFloatValue = pEnv->GetMethodID(classFloat, "floatValue", "()F"); 00294 00295 jclass tempClassBoolean = pEnv->FindClass("java/lang/Boolean"); 00296 classBoolean = (jclass)pEnv->NewGlobalRef(tempClassBoolean); 00297 methBooleanValueOf = 00298 pEnv->GetStaticMethodID( 00299 classBoolean, "valueOf", "(Z)Ljava/lang/Boolean;"); 00300 methBooleanValue = pEnv->GetMethodID(classBoolean, "booleanValue", "()Z"); 00301 00302 methBase64Decode = pEnv->GetStaticMethodID( 00303 classRhBase64,"decode","(Ljava/lang/String;)[B"); 00304 methRandomUUID = pEnv->GetStaticMethodID( 00305 classUUID,"randomUUID","()Ljava/util/UUID;"); 00306 00307 methFarragoTransformInit = pEnv->GetMethodID( 00308 classFarragoTransform, "init", 00309 "(Lnet/sf/farrago/runtime/FarragoRuntimeContext;Ljava/lang/String;[Lnet/sf/farrago/runtime/FarragoTransform$InputBinding;)V"); 00310 methFarragoTransformExecute = pEnv->GetMethodID( 00311 classFarragoTransform, "execute", "(Ljava/nio/ByteBuffer;J)I"); 00312 methFarragoTransformRestart = pEnv->GetMethodID( 00313 classFarragoTransform, "restart", "()V"); 00314 methFarragoTransformSetInputFetchTimeout = pEnv->GetMethodID( 00315 classFarragoTransform, "setInputFetchTimeout", "(J)V"); 00316 methFarragoTransformInputBindingCons = 00317 pEnv->GetMethodID( 00318 classFarragoTransformInputBinding, "", 00319 "(Ljava/lang/String;I)V"); 00320 methFarragoRuntimeContextStatementClassForName = 00321 pEnv->GetMethodID( 00322 classFarragoRuntimeContext, 00323 "statementClassForName", 00324 "(Ljava/lang/String;)Ljava/lang/Class;"); 00325 methFarragoRuntimeContextFindFarragoTransform = 00326 pEnv->GetMethodID( 00327 classFarragoRuntimeContext, 00328 "findFarragoTransform", 00329 "(Ljava/lang/String;)Lnet/sf/farrago/runtime/FarragoTransform;"); 00330 00331 jclass tempClassUtil = pEnv->FindClass("org/eigenbase/util/Util"); 00332 classUtil = (jclass) pEnv->NewGlobalRef(tempClassUtil); 00333 methUtilGetStackTrace = pEnv->GetStaticMethodID( 00334 classUtil, "getStackTrace", 00335 "(Ljava/lang/Throwable;)Ljava/lang/String;"); 00336 00337 return jniVersion; 00338 } 00339 00340 JNIEnv *JniUtil::getAttachedJavaEnv(bool &needDetach) 00341 { 00342 void *pEnv = NULL; 00343 jint rc = pVm->GetEnv(&pEnv,jniVersion); 00344 if (rc == JNI_OK) { 00345
00346 needDetach = false; 00347 return static_cast<JNIEnv *>(pEnv); 00348 } 00349 needDetach = true; 00350 rc = pVm->AttachCurrentThread(&pEnv,NULL); 00351 assert(rc == 0); 00352 assert(pEnv); 00353 return static_cast<JNIEnv *>(pEnv); 00354 } 00355 00356 void JniUtil::detachJavaEnv() 00357 { 00358 jint rc = pVm->DetachCurrentThread(); 00359 assert(rc == 0); 00360 } 00361 00362 std::string JniUtil::getClassName(jclass jClass) 00363 { 00364 JniEnvAutoRef pEnv; 00365 jstring jString = reinterpret_cast( 00366 pEnv->CallObjectMethod(jClass,methGetClassName)); 00367 assert(jString); 00368 return toStdString(pEnv,jString); 00369 } 00370 00371 std::string JniUtil::getFirstPublicInterfaceName(jclass jClass) 00372 { 00373 JniEnvAutoRef pEnv; 00374 00375 jobjectArray ifaces = 00376 reinterpret_cast( 00377 pEnv->CallObjectMethod(jClass, methGetInterfaces)); 00378 assert(ifaces); 00379 00380 for (jsize i = 0, len = pEnv->GetArrayLength(ifaces); i < len; i++) { 00381 jclass iface = 00382 reinterpret_cast( 00383 pEnv->GetObjectArrayElement(ifaces, i)); 00384 assert(iface); 00385 00386 jint modifiers = 00387 pEnv->CallIntMethod(iface, methGetModifiers); 00388 00389 jboolean isPublic = 00390 pEnv->CallStaticBooleanMethod( 00391 classModifier, methIsPublic, modifiers); 00392 00393 if (isPublic) { 00394 return getClassName(iface); 00395 } 00396 } 00397 00398 return std::string("(none)"); 00399 } 00400 00401 std::string JniUtil::toStdString(JniEnvRef pEnv,jstring jString) 00402 { 00403 const char *pChars = pEnv->GetStringUTFChars(jString,NULL); 00404 assert(pChars); 00405 std::string str(pChars,pEnv->GetStringUTFLength(jString)); 00406 pEnv->ReleaseStringUTFChars(jString,pChars); 00407 return str; 00408 } 00409 00410 jstring JniUtil::toString(JniEnvRef pEnv,jobject jObject) 00411 { 00412 return reinterpret_cast( 00413 pEnv->CallObjectMethod(jObject,methToString)); 00414 } 00415 00416 uint JniUtil::lookUpEnum(std::string *pSymbols,std::string const &symbol) 00417 { 00418 for (uint i = 0; ; ++i) { 00419 assert(pSymbols[i].size()); 00420 if (pSymbols[i] == symbol) { 00421 return i; 00422 } 00423 } 00424 } 00425 00426 jobject JniUtil::getIter(JniEnvRef pEnv,jobject jCollection) 00427 { 00428 return pEnv->CallObjectMethod(jCollection,methIterator); 00429 } 00430 00431 jobject JniUtil::getNextFromIter(JniEnvRef pEnv,jobject jIter) 00432 { 00433 if (!pEnv->CallBooleanMethod(jIter,methHasNext)) { 00434 return NULL; 00435 } 00436 return pEnv->CallObjectMethod(jIter,methNext); 00437 } 00438 00439 void JniUtil::incrementHandleCount(const char *pType, const void *pHandle) 00440 { 00441 ++handleCount; 00442 00443 traceHandleCount("INC", pType, pHandle); 00444 } 00445 00446 void JniUtil::decrementHandleCount(const char *pType, const void *pHandle) 00447 { 00448 --handleCount; 00449 00450 assert(handleCount >= 0); 00451 00452 traceHandleCount("DEC", pType, pHandle); 00453 } 00454 00455 void JniUtil::traceHandleCount( 00456 const char *pAction, const char *pType, const void *pHandle) 00457 { 00458 if (traceHandleCountEnabled) { 00459 handleCountTraceStream 00460 << pAction << " " << pType << ": " << pHandle << std::endl; 00461 00462 if (handleCount == 0 && closeHandleCountTraceOnZero && 00463 strcmp(pAction, "DEC") == 0) { 00464 traceHandleCountEnabled = false; 00465 closeHandleCountTraceOnZero = false; 00466 00467 handleCountTraceStream.flush(); 00468 handleCountTraceStream.close(); 00469 } 00470 } 00471 } 00472 00473 std::string JniUtil::getXmi(const TupleDescriptor &tupleDescriptor) 00474 { 00475 std::ostringstream oss; 00476 oss << "<XMI xmi.version = '1.2' " 00477 << "xmlns:FEMFennel = 'org.omg.xmi.namespace.FEMFennel'>" << std::endl; 00478 oss << "<XMI.content>" << std::endl; 00479 oss << "FEMFennel:TupleDescriptor" << std::endl; 00480 for (uint i = 0; i < tupleDescriptor.size(); ++i) { 00481 TupleAttributeDescriptor const &attrDescriptor = 00482 tupleDescriptor[i]; 00483 oss << "FEMFennel:TupleDescriptor.AttrDescriptor"; 00484 oss << "<FEMFennel:TupleAttrDescriptor "; 00485 oss << "typeOrdinal='"; 00486 oss << attrDescriptor.pTypeDescriptor->getOrdinal(); 00487 oss << "' "; 00488 oss << "isNullable='"; 00489 oss << (attrDescriptor.isNullable ? "true" : "false"); 00490 oss << "' "; 00491 oss << "byteLength='"; 00492 oss << attrDescriptor.cbStorage; 00493 oss << "' "; 00494 oss << "/>" << std::endl; 00495 oss << "</FEMFennel:TupleDescriptor.AttrDescriptor>"; 00496 } 00497 oss << "" << std::endl; 00498 oss << "</XMI.content>" << std::endl; 00499 oss << "" << std::endl; 00500 std::string s = oss.str(); 00501 return s; 00502 } 00503 00504 ThreadTracker &JniUtil::getThreadTracker() 00505 { 00506 return threadTracker; 00507 } 00508 00509 void JniExceptionChecker::checkExceptions() 00510 { 00511 jthrowable excn = pEnv->ExceptionOccurred(); 00512 if (excn) { 00513 pEnv->ExceptionClear(); 00514 throw JavaExcn(excn); 00515 } 00516 } 00517 00518 JniExceptionChecker::~JniExceptionChecker() 00519 { 00520 checkExceptions(); 00521 } 00522 00523 JniEnvAutoRef::JniEnvAutoRef() 00524 : JniEnvRef(JniUtil::getAttachedJavaEnv(needDetach)) 00525 { 00526 } 00527 00528 JniEnvAutoRef::~JniEnvAutoRef() 00529 { 00530 if (needDetach) { 00531 JniUtil::detachJavaEnv(); 00532 } 00533 } 00534 00535 void JniEnvAutoRef::suppressDetach() 00536 { 00537 needDetach = false; 00538 } 00539 00540 void JniEnvRef::handleExcn(std::exception &ex) 00541 { 00542 JavaExcn *pJavaExcn = dynamic_cast<JavaExcn *>(&ex); 00543 if (pJavaExcn) { 00544 pEnv->Throw(pJavaExcn->getJavaException()); 00545 return; 00546 } 00547 std::string what; 00548 FennelExcn *pFennelExcn = dynamic_cast<FennelExcn *>(&ex); 00549 if (pFennelExcn) { 00550 what = pFennelExcn->getMessage(); 00551 } else { 00552 std::bad_alloc *pBadAllocExcn = 00553 dynamic_cast<std::bad_alloc *>(&ex); 00554 if (pBadAllocExcn) { 00555
00556
00557 what = FennelResource::instance().internalError("malloc failed"); 00558 } else { 00559 what = FennelResource::instance().internalError(ex.what()); 00560 } 00561 } 00562
00563 jclass classSQLException = pEnv->FindClass("java/sql/SQLException"); 00564 jstring jMessage = pEnv->NewStringUTF(what.c_str()); 00565 jmethodID constructor = pEnv->GetMethodID( 00566 classSQLException,"","(Ljava/lang/String;)V"); 00567 jthrowable t = (jthrowable) 00568 pEnv->NewObject(classSQLException,constructor,jMessage); 00569 pEnv->Throw(t); 00570 } 00571 00572 void JniPseudoUuidGenerator::generateUuid(PseudoUuid &pseudoUuid) 00573 { 00574 JniEnvAutoRef pEnv; 00575 jobject jUuid = pEnv->CallStaticObjectMethod( 00576 JniUtil::classUUID, 00577 JniUtil::methRandomUUID); 00578 jstring jsUuid = JniUtil::toString(pEnv, jUuid); 00579 std::string sUuid = JniUtil::toStdString(pEnv, jsUuid); 00580 pseudoUuid.parse(sUuid); 00581 } 00582 00583 FENNEL_END_CPPFILE("$Id: //open/dev/fennel/farrago/JniUtil.cpp#35 $"); 00584 00585