void onProcessCreation() throw ( ::jace::JNIException ) { #ifdef SUPPORTS_PTHREADS int rc = pthread_key_create( &CLASSLOADER_KEY, classLoaderDestructor ); switch ( rc ) { case 0: break; case ENOMEM: case EAGAIN: { std::string msg = "Out of memory"; throw JNIException( msg ); } default: { std::string msg = "JNIHelper::setClassLoader()\n" "phread_key_create() returned " + std::to_string( rc ) + "."; throw JNIException( msg ); } } #elif _WIN32 CLASSLOADER_KEY = TlsAlloc(); if ( CLASSLOADER_KEY == TLS_OUT_OF_INDEXES ) { std::string msg = "JNIHelper::setClassLoader()\n" "TlsAlloc() returned " + std::to_string( GetLastError() ) + "."; throw JNIException( msg ); } #endif }
JavaVM* getJavaVM() throw ( JNIException ) { if ( ! javaVM ) { jsize numVMs; if (globalLoader.get() == 0) { string msg = string( "JNIHelper::getJavaVM\n" ) + "Unable to find the JVM loader"; throw JNIException( msg ); } jint result = globalLoader->getCreatedJavaVMs( &javaVM, 1, &numVMs ); if ( result != 0 ) { string msg = string( "JNIHelper::getJavaVM\n" ) + "Unable to find the JVM. The specific JNI error code is " + std::to_string( result ); throw JNIException( msg ); } if ( numVMs != 1 ) { string msg = string( "JNIHelper::getJavaVM\n" ) + "Looking for exactly 1 JVM, but " + std::to_string( numVMs ) + " were found."; throw JNIException( msg ); } } return javaVM; }
jclass JClassImpl::getClass() const throw ( JNIException ) { if ( mClass ) { return mClass; } JNIEnv* env = helper::attach(); jobject classLoader = jace::helper::getClassLoader(); jclass localClass; if ( classLoader != 0 ) { std::string binaryName( getName() ); // Replace '/' by '.' in the name std::replace(binaryName.begin(), binaryName.end(), '/', '.'); jclass classLoaderClass = env->GetObjectClass( classLoader ); jmethodID loadClass = env->GetMethodID( classLoaderClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;" ); if ( loadClass == 0 ) { string msg = "JClass::getClass - Unable to find the method JNIHelper::getClassLoader().loadClass()"; try { helper::catchAndThrow(); } catch (JNIException& e) { msg.append("\ncaused by:\n"); msg.append(e.what()); } throw JNIException( msg ); } jstring javaString = env->NewStringUTF( binaryName.c_str() ); localClass = static_cast<jclass>( env->CallObjectMethod( classLoader, loadClass, javaString ) ); env->DeleteLocalRef( javaString ); } else { localClass = env->FindClass( getName().c_str() ); } if ( ! localClass ) { string msg = "JClass::getClass - Unable to find the class <" + getName() + ">"; try { helper::catchAndThrow(); } catch (JNIException& e) { msg.append("\ncaused by:\n"); msg.append(e.what()); } throw JNIException( msg ); } mClass = static_cast<jclass>( helper::newGlobalRef( env, localClass ) ); helper::deleteLocalRef( env, localClass ); return mClass; }
std::string toString( jobject obj ) { JNIEnv* env = attach(); jclass objectClass = env->FindClass( "java/lang/Object" ); if ( ! objectClass ) { string msg = "Assert failed: Unable to find the class, java.lang.Object."; try { helper::catchAndThrow(); } catch (JNIException& e) { msg.append("\ncaused by:\n"); msg.append(e.what()); } throw JNIException( msg ); } jmethodID toString = env->GetMethodID( objectClass, "toString", "()Ljava/lang/String;" ); if ( ! toString ) { string msg = "Assert failed: Unable to find the method, Object.toString()."; try { helper::catchAndThrow(); } catch (JNIException& e) { msg.append("\ncaused by:\n"); msg.append(e.what()); } throw JNIException( msg ); } jstring javaStr = static_cast<jstring>( env->CallObjectMethod( obj, toString ) ); const char* strBuf = env->GetStringUTFChars( javaStr, 0 ); string value = string( strBuf ); env->ReleaseStringUTFChars( javaStr, strBuf ); deleteLocalRef( env, javaStr ); deleteLocalRef( env, objectClass ); return value; }
void onProcessDestruction() throw ( ::jace::JNIException ) { #ifdef SUPPORTS_PTHREADS int rc = pthread_key_delete( CLASSLOADER_KEY ); if ( rc != 0 ) { std::string msg = "JNIHelper::setClassLoader()\n" "thread_key_delete() returned " + std::to_string( rc ) + "."; throw JNIException( msg ); } #elif _WIN32 BOOL rc = TlsFree( CLASSLOADER_KEY ); if ( !rc ) { std::string msg = "JNIHelper::setClassLoader()\n" "TlsFree() returned " + std::to_string( GetLastError() ) + "."; throw JNIException( msg ); } #endif }
/** * Gets the method id matching the given arguments. * */ jmethodID JConstructor::getMethodID( const JClass* jClass, const JArguments& arguments ) { /* We cache the jmethodID locally, so if we've already found it, * we don't need to go looking for it again. */ if ( mMethodID ) { return mMethodID; } /* If we don't already have the jmethodID, we need to determine * the signature of this method. */ /* We construct this signature with a void return type, * because the return type for constructors is void. */ JSignature signature( *JVoid::staticGetJavaJniClass() ); typedef list<JValue*> ValueList; ValueList args = arguments.asList(); ValueList::iterator i = args.begin(); ValueList::iterator end = args.end(); for ( ; i != end; ++i ) { JValue* value = *i; signature << *value->getJavaJniClass(); } string methodSignature = signature.toString(); /* Now that we have the signature for the method, we could look * in a global cache for the jmethodID corresponding to this method, * but for now, we'll always find it. */ JNIEnv* env = helper::attach(); mMethodID = env->GetMethodID( jClass->getClass(), "<init>", methodSignature.c_str() ); if ( mMethodID == NULL ) { string msg = string( "JConstructor::getMethodID\n" ) + "Unable to find a constructor for " + jClass->getName() + "\n" + "The signature is <" + methodSignature + ">"; try { helper::catchAndThrow(); } catch (JNIException e) { msg.append("\ncaused by:\n"); msg.append(e.what()); } throw JNIException( msg ); } return mMethodID; }
std::string asString( JNIEnv* env, jstring str ) { const char* utfString = env->GetStringUTFChars( str, 0 ); if ( ! utfString ) { std::string msg = "Unable to retrieve the character string for an exception message."; throw JNIException( msg ); } std::string stdString = utfString; env->ReleaseStringUTFChars( str, utfString ); return stdString; }
JNIEnv* attach() throw ( JNIException ) { if ( globalHasShutdown ) { throw JNIException( "The VM has already been shutdown." ); } JNIEnv* env; jint result = getJavaVM()->AttachCurrentThread( reinterpret_cast<void**>( &env ), 0 ); if ( result != 0 ) { string msg = "JNIHelper::attach\n" \ "Unable to attach the current thread. The specific JNI error code is " + std::to_string( result ); throw JNIException( msg ); } return env; }
jobject newGlobalRef( JNIEnv* env, jobject ref ) { jobject globalRef = env->NewGlobalRef( ref ); if ( ! globalRef ) { string msg = string( "JNIHelper::newGlobalRef\n" ) + "Unable to create a new global reference.\n" + "It is likely that you have exceeded the max heap size of your virtual machine."; throw JNIException( msg ); } return globalRef; }
jobject newLocalRef( JNIEnv* env, jobject ref ) { jobject localRef = env->NewLocalRef( ref ); if ( ! localRef ) { string msg = string( "JNIHelper::newLocalRef\n" ) + "Unable to create a new local reference.\n" + "It is likely that you have exceeded the maximum local reference count.\n" + "You can increase the maximum count with a call to EnsureLocalCapacity()."; throw JNIException( msg ); } return localRef; }
void setClassLoader(jobject classLoader) { JNIEnv* env = attach(); jobject oldRef = getClassLoader(); #ifdef SUPPORTS_PTHREADS int rc; #elif _WIN32 BOOL rc; #endif // Set the new value if ( classLoader != 0 ) { classLoader = static_cast<jobject> ( newGlobalRef( env, classLoader ) ); } #ifdef SUPPORTS_PTHREADS rc = pthread_setspecific( CLASSLOADER_KEY, classLoader ); if ( rc != 0 ) { std::string msg = "JNIHelper::setClassLoader()\n" "pthread_setspecific() returned " + std::to_string( rc ) + "."; throw JNIException( msg ); } #elif _WIN32 rc = TlsSetValue( CLASSLOADER_KEY, classLoader ); if ( !rc ) { std::string msg = "JNIHelper::setClassLoader()\n" "TlsSetValue() returned " + std::to_string( GetLastError() ) + "."; throw JNIException( msg ); } #endif // Delete the old value if necessary if ( oldRef != 0 ) { classLoaderDestructor( oldRef ); } }
QString getJavaProperty(QString name) { JNIEnv* env = attach(); jclass systemClass = env->FindClass("java/lang/System"); if (systemClass) { jmethodID getProperty = env->GetStaticMethodID(systemClass, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"); if (getProperty) { const char* propUtf = name.toStdString().c_str(); jstring property = env->NewStringUTF(propUtf); jstring result = (jstring) env->CallStaticObjectMethod(systemClass, getProperty, property); const char* resUtf = env->GetStringUTFChars(result, NULL); QString returnValue (resUtf); env->DeleteLocalRef(result); env->DeleteLocalRef(property); env->DeleteLocalRef(systemClass); return returnValue; } else { throw JNIException("cannot find System.getProperty method"); } } else { throw JNIException("cannot find System class"); } }
void JNIHandleException() { jthrowable exception = JNIObject::getJNIEnv()->ExceptionOccurred(); if ( exception ) { JNIObject::getJNIEnv()->ExceptionDescribe(); JNIObject::getJNIEnv()->ExceptionClear(); const char* exceptionClassName = JNIGetClassName( exception ); if ( !exceptionClassName ) // TODO: fix, doesn't seem to ever be working, will remove need for describe and allow us to mirror with explicit C++ exception classes { // TODO: handle gracefully but don't let go unnoticed! JNIObject::getJNIEnv()->ExceptionClear(); exceptionClassName = "Unknown exception"; } JNIObject::getJNIEnv()->DeleteLocalRef( exception ); throw JNIException( exceptionClassName ); } }
Object ExpressionParser::evaluate(QString expression) { QStringList parts = expression.split("."); QString str(parts.at(0)); str.replace('/', '.'); str.replace(" ", ""); str.replace("()", ""); Class cls = Class::forName(str); if (parts.size() == 1) { return cls; } Object obj = cls.getStaticFieldContent(parts.at(1)); for (int nextField = 2; nextField < parts.size(); nextField++) { if (obj.isNull()) { throw JNIException("Dereferenced NULL at position: " % QString::number(nextField)); } Class objClass = obj.getClass(); QString fieldName = convertFieldName(obj, parts.at(nextField)); obj = objClass.getFieldContent(fieldName, obj); } return obj; }
void checkAndThrow(QString context, const char* file, int line) throw(JNIException) { JNIEnv* env = attach(); if (!env->ExceptionCheck()) { return; } jthrowable thrown = env->ExceptionOccurred(); env->ExceptionClear(); jclass throwable = env->FindClass("java/lang/Throwable"); if ( !throwable ) throw JNIException("Assert failed: Could not find Throwable class"); jmethodID getMessage = env->GetMethodID(throwable, "getMessage", "()Ljava/lang/String;"); if ( !getMessage ) throw JNIException("Assert failed: Could not find Throwable.getMessage() method"); jmethodID getClass = env->GetMethodID(throwable, "getClass", "()Ljava/lang/Class;"); if ( !getClass ) throw JNIException("Assert failed: Could not find Throwable.getClass() method"); jclass classClass = env->FindClass("java/lang/Class"); if ( !classClass ) throw JNIException("Assert failed: Could not find Class class"); jmethodID classGetName = env->GetMethodID(classClass, "getName", "()Ljava/lang/String;"); if ( !classGetName ) throw JNIException("Assert failed: Could not find Class.getName() method"); jobject type = env->CallObjectMethod(thrown, getClass); jstring jmessage = static_cast<jstring>(env->CallObjectMethod(thrown, getMessage)); jstring jname = static_cast<jstring>(env->CallObjectMethod(type, classGetName)); string message = jmessage == NULL ? "No Message" : asString(env, jmessage); string name = jname == NULL ? "Unknown Type" : asString(env, jname); env->DeleteLocalRef(throwable); env->DeleteLocalRef(thrown); env->DeleteLocalRef(classClass); env->DeleteLocalRef(jmessage); env->DeleteLocalRef(jname); throw JNIException(context % " (in " % file % ":" % QString::number(line) % ")\nCaused by " % name.c_str() % ": " % message.c_str()); }
void catchAndThrow() { JNIEnv* env = attach(); if ( ! env->ExceptionCheck() ) { return; } jthrowable jexception = env->ExceptionOccurred(); env->ExceptionClear(); /* Find the fully qualified name for the exception type, so * we can find a matching C++ proxy exception. * * In java, this looks like: * String typeName = exception.getClass().getName(); */ jclass throwableClass = env->FindClass( "java/lang/Throwable" ); if ( ! throwableClass ) { string msg = "Assert failed: Unable to find the class, java.lang.Throwable."; throw JNIException( msg ); } jclass classClass = env->FindClass( "java/lang/Class" ); if ( ! classClass ) { string msg = "Assert failed: Unable to find the class, java.lang.Class."; throw JNIException( msg ); } jmethodID throwableGetClass = env->GetMethodID( throwableClass, "getClass", "()Ljava/lang/Class;" ); if ( ! throwableGetClass ) { string msg = "Assert failed: Unable to find the method, Throwable.getClass()."; throw JNIException( msg ); } deleteLocalRef( env, throwableClass ); jmethodID classGetName = env->GetMethodID( classClass, "getName", "()Ljava/lang/String;" ); if ( ! classGetName ) { string msg = "Assert failed: Unable to find the method, Class.getName()."; throw JNIException( msg ); } jmethodID classGetSuperclass = env->GetMethodID( classClass, "getSuperclass", "()Ljava/lang/Class;" ); if ( ! classGetSuperclass ) { string msg = "Assert failed: Unable to find the method, Class.getSuperclass()."; throw JNIException( msg ); } deleteLocalRef( env, classClass ); jobject exceptionClass = env->CallObjectMethod( jexception, throwableGetClass ); if ( env->ExceptionOccurred() ) { env->ExceptionDescribe(); string msg = "helper::catchAndThrow()\n" \ "An error occurred while trying to call getClass() on the thrown exception."; throw JNIException( msg ); } jstring exceptionType = static_cast<jstring>( env->CallObjectMethod( exceptionClass, classGetName ) ); if ( env->ExceptionOccurred() ) { env->ExceptionDescribe(); string msg = "helper::catchAndThrow()\n" \ "An error occurred while trying to call getName() on the class of the thrown exception."; throw JNIException( msg ); } string exceptionTypeString = asString( env, exceptionType ); /* Now, find the matching factory for this exception type. */ while ( true ) { FactoryMap::iterator it = getFactoryMap()->find( exceptionTypeString ); /* If we couldn't find a match, try to find the parent exception type. */ if ( it == getFactoryMap()->end() ) { jobject superClass = env->CallObjectMethod( exceptionClass, classGetSuperclass ); if ( env->ExceptionOccurred() ) { env->ExceptionDescribe(); string msg = "helper::catchAndThrow()\n" \ "An error occurred while trying to call getSuperclass() on the thrown exception."; throw JNIException( msg ); } /* We get NULL if we've already reached java.lang.Object, in which case, * we couldn't find any match at all. */ if ( ! superClass ) { break; } deleteLocalRef( env, exceptionClass ); deleteLocalRef( env, exceptionType ); exceptionClass = superClass; exceptionType = static_cast<jstring>( env->CallObjectMethod( exceptionClass, classGetName ) ); if ( env->ExceptionOccurred() ) { env->ExceptionDescribe(); string msg = "helper::catchAndThrow()\n" \ "An error occurred while trying to call getName() on the superclass " \ "of the thrown exception."; throw JNIException( msg ); } exceptionTypeString = asString( env, exceptionType ); if ( exceptionTypeString == "java.lang.Object" ) { /* * Couldn't find a matching exception. Abort! */ break; } continue; } /* Ask the factory to throw the exception. */ jvalue value; value.l = jexception; it->second->throwInstance( value ); } exceptionClass = env->CallObjectMethod( jexception, throwableGetClass ); if ( env->ExceptionOccurred() ) { env->ExceptionDescribe(); string msg = "helper::catchAndThrow()\n" \ "An error occurred while trying to call getClass() on the thrown exception."; throw JNIException( msg ); } exceptionType = static_cast<jstring>( env->CallObjectMethod( exceptionClass, classGetName ) ); if ( env->ExceptionOccurred() ) { env->ExceptionDescribe(); string msg = "helper::catchAndThrow()\n" \ "An error occurred while trying to call getName() on the class of the thrown exception."; throw JNIException( msg ); } // Fallback: throw a JNIException with the type name and message of the Throwable. exceptionTypeString = asString( env, exceptionType ); jmethodID getMessage = env->GetMethodID(static_cast<jclass>(exceptionClass), "getMessage", "()Ljava/lang/String;"); if ( !getMessage) { throw JNIException("Could not find Throwable.getMessage() method"); } jstring jmessage = static_cast<jstring>( env->CallObjectMethod(jexception, getMessage)); if ( !jmessage) { // No message specified (or some error in the JVM), so just print the Exception type. throw JNIException(string("Exception occurred in JVM: ") + exceptionTypeString); } const char *msg = env->GetStringUTFChars(jmessage, NULL); throw JNIException( exceptionTypeString + ": " + msg ); }
void createVm( const VmLoader& loader, const OptionList& options, bool ignoreUnrecognized ) { globalLoader = std::unique_ptr<VmLoader>( loader.clone() ); globalLoader->loadVm(); JavaVM* vm; JNIEnv* env; JavaVMInitArgs vm_args; JavaVMOption* jniOptions = options.createJniOptions(); vm_args.version = globalLoader->version(); vm_args.options = jniOptions; vm_args.nOptions = jint( options.size() ); vm_args.ignoreUnrecognized = ignoreUnrecognized; jint rc = globalLoader->createJavaVM( &vm, reinterpret_cast<void**>( &env ), &vm_args ); options.destroyJniOptions( jniOptions ); if ( rc != 0 ) { string msg = "Unable to create the virtual machine. The error was " + std::to_string( rc ); throw JNIException( msg ); } jclass runtimeClass = env->FindClass( "java/lang/Runtime" ); if ( ! runtimeClass ) { string msg = "Assert failed: Unable to find the class, java.lang.Runtime."; throw JNIException( msg ); } jmethodID runtimeGetRuntime = env->GetStaticMethodID( runtimeClass, "getRuntime", "()Ljava/lang/Runtime;" ); if ( ! runtimeGetRuntime ) { deleteLocalRef( env, runtimeClass ); string msg = "Assert failed: Unable to find the method, Runtime.getRuntime()."; throw JNIException( msg ); } jobject runtimeObject = env->CallStaticObjectMethod( runtimeClass, runtimeGetRuntime ); if ( ! runtimeObject ) { deleteLocalRef( env, runtimeClass ); string msg = "Unable to invoke Runtime.getRuntime()"; try { helper::catchAndThrow(); } catch (JNIException& e) { msg.append("\ncaused by:\n"); msg.append(e.what()); } throw JNIException( msg ); } jmethodID runtimeAddShutdownHook = env->GetMethodID( runtimeClass, "addShutdownHook", "(Ljava/lang/Thread;)V" ); if ( ! runtimeAddShutdownHook ) { deleteLocalRef( env, runtimeObject ); deleteLocalRef( env, runtimeClass ); string msg = "Assert failed: Unable to find the method, Runtime.addShutdownHook()."; throw JNIException( msg ); } jclass shutdownHookClass = env->FindClass( "jace/util/ShutdownHook" ); if ( ! shutdownHookClass ) { deleteLocalRef( env, runtimeObject ); deleteLocalRef( env, runtimeClass ); string msg = "Assert failed: Unable to find the class, jace.util.ShutdownHook. Did you forget to include " "jace-runtime.jar in your classpath at runtime?"; throw JNIException( msg ); } // Register the native method jace.util.ShutdownHook.signalVMShutdown JNINativeMethod signalVMShutdown; signalVMShutdown.fnPtr = reinterpret_cast<void*>(Java_jace_util_ShutdownHook_signalVMShutdown); signalVMShutdown.name = const_cast<char*>("signalVMShutdown"); signalVMShutdown.signature = const_cast<char*>("()V"); jint result = env->RegisterNatives(shutdownHookClass, &signalVMShutdown, 1); if (result != JNI_OK) { deleteLocalRef( env, runtimeObject ); deleteLocalRef( env, runtimeClass ); deleteLocalRef( env, shutdownHookClass ); string msg = "Assert failed: Unable to register native method, jace.util.ShutdownHook.signalVMShutdown()"; throw JNIException( msg ); } jmethodID shutdownHookGetInstance = env->GetStaticMethodID( shutdownHookClass, "getInstance", "()Ljace/util/ShutdownHook;" ); if ( ! shutdownHookGetInstance ) { deleteLocalRef( env, runtimeObject ); deleteLocalRef( env, runtimeClass ); deleteLocalRef( env, shutdownHookClass ); string msg = "Assert failed: Unable to find the method, jace.util.ShutdownHook.getInstance()"; throw JNIException( msg ); } jobject shutdownHookObject = env->CallStaticObjectMethod( shutdownHookClass, shutdownHookGetInstance ); if ( ! shutdownHookObject ) { deleteLocalRef( env, runtimeObject ); deleteLocalRef( env, runtimeClass ); deleteLocalRef( env, shutdownHookClass ); string msg = "Unable to invoke jace.util.ShutdownHook.getInstance()"; try { helper::catchAndThrow(); } catch (JNIException& e) { msg.append("\ncaused by:\n"); msg.append(e.what()); } throw JNIException( msg ); } env->CallVoidMethod( runtimeObject, runtimeAddShutdownHook, shutdownHookObject ); try { helper::catchAndThrow(); } catch (JNIException& e) { string msg = "Exception thrown invoking Runtime.addShutdownHook(shutdownHook)"; msg.append("\ncaused by:\n"); msg.append(e.what()); throw JNIException( msg ); } deleteLocalRef( env, runtimeObject ); deleteLocalRef( env, runtimeClass ); deleteLocalRef( env, shutdownHookClass ); }