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 ¶ms)
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, "<init>",
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<jstring>(
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<jobjectArray>(
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<jclass>(
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<jstring>(
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 << "</FEMFennel:TupleDescriptor>" << std::endl;
00498 oss << "</XMI.content>" << std::endl;
00499 oss << "</XMI>" << 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,"<init>","(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