You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by be...@apache.org on 2011/06/05 11:29:36 UTC
svn commit: r1132352 - /incubator/mesos/trunk/src/java/jni/convert.cpp
Author: benh
Date: Sun Jun 5 09:29:35 2011
New Revision: 1132352
URL: http://svn.apache.org/viewvc?rev=1132352&view=rev
Log:
Fixed Mesos Java library for environments where the Mesos classes are
not available through the system classloader, such as Scala. (Ported
the solution that existed before the protobuf switch).
Modified:
incubator/mesos/trunk/src/java/jni/convert.cpp
Modified: incubator/mesos/trunk/src/java/jni/convert.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/java/jni/convert.cpp?rev=1132352&r1=1132351&r2=1132352&view=diff
==============================================================================
--- incubator/mesos/trunk/src/java/jni/convert.cpp (original)
+++ incubator/mesos/trunk/src/java/jni/convert.cpp Sun Jun 5 09:29:35 2011
@@ -1,6 +1,7 @@
#include <jni.h>
#include <string>
+#include <assert.h>
#include <mesos/mesos.hpp>
@@ -10,6 +11,125 @@ using namespace mesos;
using std::string;
+// Facilities for loading Mesos-related classes with the correct ClassLoader.
+// Unfortunately, JNI's FindClass uses the system ClassLoader when it is
+// called from a C++ thread, but in Scala (and probably other Java
+// environments too), this ClassLoader is not enough to locate mesos.jar.
+// Instead, we try to capture Thread.currentThread()'s context ClassLoader
+// when the Mesos library is initialized, in case it has more paths that
+// we can search. We store this in mesosClassLoader and access it through
+// FindMesosClass(). We initialize the mesosClassLoader variable in
+// JNI_OnLoad and uninitialize it in JNI_OnUnLoad (see below).
+//
+// This code is based on Apache 2 licensed Android code obtained from
+// http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/jni/AndroidRuntime.cpp;h=f61e2476c71191aa6eabc93bcb26b3c15ccf6136;hb=HEAD
+namespace {
+
+jweak mesosClassLoader = NULL; // Initialized in JNI_OnLoad later in this file.
+
+
+jclass FindMesosClass(JNIEnv* env, const char* className)
+{
+ if (env->ExceptionCheck()) {
+ fprintf(stderr, "ERROR: exception pending on entry to "
+ "FindMesosClass()\n");
+ return NULL;
+ }
+
+ if (mesosClassLoader == NULL) {
+ return env->FindClass(className);
+ }
+
+ /*
+ * JNI FindClass uses class names with slashes, but ClassLoader.loadClass
+ * uses the dotted "binary name" format. Convert formats.
+ */
+ std::string convName = className;
+ for (int i = 0; i < convName.size(); i++) {
+ if (convName[i] == '/')
+ convName[i] = '.';
+ }
+
+ jclass javaLangClassLoader = env->FindClass("java/lang/ClassLoader");
+ assert(javaLangClassLoader != NULL);
+ jmethodID loadClass = env->GetMethodID(javaLangClassLoader,
+ "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+ assert(loadClass != NULL);
+ jclass cls = NULL;
+
+ /* create an object for the class name string; alloc could fail */
+ jstring strClassName = env->NewStringUTF(convName.c_str());
+ if (env->ExceptionCheck()) {
+ fprintf(stderr, "ERROR: unable to convert '%s' to string\n", convName.c_str());
+ goto bail;
+ }
+
+ /* try to find the named class */
+ cls = (jclass) env->CallObjectMethod(mesosClassLoader, loadClass,
+ strClassName);
+ if (env->ExceptionCheck()) {
+ fprintf(stderr, "ERROR: unable to load class '%s' from %p\n",
+ className, mesosClassLoader);
+ cls = NULL;
+ goto bail;
+ }
+
+bail:
+ return cls;
+}
+
+} /* namespace { */
+
+
+// Called by JVM when it loads our library
+JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* jvm, void* reserved)
+{
+ // Grab the context ClassLoader of the current thread, if any
+
+ JNIEnv* env;
+ if (jvm->GetEnv((void **)&env, JNI_VERSION_1_2)) {
+ return JNI_ERR; /* JNI version not supported */
+ }
+
+ jclass javaLangThread, javaLangClassLoader;
+ jmethodID currentThread, getContextClassLoader, loadClass;
+ jobject thread, classLoader;
+
+ /* find this thread's context class loader; none of this is expected to fail */
+ javaLangThread = env->FindClass("java/lang/Thread");
+ assert(javaLangThread != NULL);
+ javaLangClassLoader = env->FindClass("java/lang/ClassLoader");
+ assert(javaLangClassLoader != NULL);
+ currentThread = env->GetStaticMethodID(javaLangThread,
+ "currentThread", "()Ljava/lang/Thread;");
+ getContextClassLoader = env->GetMethodID(javaLangThread,
+ "getContextClassLoader", "()Ljava/lang/ClassLoader;");
+ assert(currentThread != NULL);
+ assert(getContextClassLoader != NULL);
+ thread = env->CallStaticObjectMethod(javaLangThread, currentThread);
+ assert(thread != NULL);
+ classLoader = env->CallObjectMethod(thread, getContextClassLoader);
+ if (classLoader != NULL) {
+ mesosClassLoader = env->NewWeakGlobalRef(classLoader);
+ }
+
+ return JNI_VERSION_1_2;
+}
+
+
+// Called by JVM when it unloads our library
+JNIEXPORT void JNICALL JNI_OnUnLoad(JavaVM* jvm, void* reserved)
+{
+ JNIEnv *env;
+ if (jvm->GetEnv((void **)&env, JNI_VERSION_1_2)) {
+ return;
+ }
+ if (mesosClassLoader != NULL) {
+ env->DeleteWeakGlobalRef(mesosClassLoader);
+ mesosClassLoader = NULL;
+ }
+}
+
template <>
jobject convert(JNIEnv* env, const string& s)
@@ -29,7 +149,7 @@ jobject convert(JNIEnv* env, const Frame
env->SetByteArrayRegion(jdata, 0, data.size(), (jbyte*) data.data());
// FrameworkID frameworkId = FrameworkID.parseFrom(data);
- jclass clazz = env->FindClass("org/apache/mesos/Protos$FrameworkID");
+ jclass clazz = FindMesosClass(env, "org/apache/mesos/Protos$FrameworkID");
jmethodID parseFrom =
env->GetStaticMethodID(clazz, "parseFrom",
@@ -52,7 +172,7 @@ jobject convert(JNIEnv* env, const Execu
env->SetByteArrayRegion(jdata, 0, data.size(), (jbyte*) data.data());
// ExecutorID executorId = ExecutorID.parseFrom(data);
- jclass clazz = env->FindClass("org/apache/mesos/Protos$ExecutorID");
+ jclass clazz = FindMesosClass(env, "org/apache/mesos/Protos$ExecutorID");
jmethodID parseFrom =
env->GetStaticMethodID(clazz, "parseFrom",
@@ -75,7 +195,7 @@ jobject convert(JNIEnv* env, const TaskI
env->SetByteArrayRegion(jdata, 0, data.size(), (jbyte*) data.data());
// TaskID taskId = TaskID.parseFrom(data);
- jclass clazz = env->FindClass("org/apache/mesos/Protos$TaskID");
+ jclass clazz = FindMesosClass(env, "org/apache/mesos/Protos$TaskID");
jmethodID parseFrom =
env->GetStaticMethodID(clazz, "parseFrom",
@@ -98,7 +218,7 @@ jobject convert(JNIEnv* env, const Slave
env->SetByteArrayRegion(jdata, 0, data.size(), (jbyte*) data.data());
// SlaveID slaveId = SlaveID.parseFrom(data);
- jclass clazz = env->FindClass("org/apache/mesos/Protos$SlaveID");
+ jclass clazz = FindMesosClass(env, "org/apache/mesos/Protos$SlaveID");
jmethodID parseFrom =
env->GetStaticMethodID(clazz, "parseFrom",
@@ -121,7 +241,7 @@ jobject convert(JNIEnv* env, const Offer
env->SetByteArrayRegion(jdata, 0, data.size(), (jbyte*) data.data());
// OfferID offerId = OfferID.parseFrom(data);
- jclass clazz = env->FindClass("org/apache/mesos/Protos$OfferID");
+ jclass clazz = FindMesosClass(env, "org/apache/mesos/Protos$OfferID");
jmethodID parseFrom =
env->GetStaticMethodID(clazz, "parseFrom",
@@ -139,7 +259,7 @@ jobject convert(JNIEnv* env, const TaskS
jint jvalue = state;
// TaskState state = TaskState.valueOf(value);
- jclass clazz = env->FindClass("org/apache/mesos/Protos$TaskState");
+ jclass clazz = FindMesosClass(env, "org/apache/mesos/Protos$TaskState");
jmethodID valueOf =
env->GetStaticMethodID(clazz, "valueOf",
@@ -162,7 +282,7 @@ jobject convert(JNIEnv* env, const TaskD
env->SetByteArrayRegion(jdata, 0, data.size(), (jbyte*) data.data());
// TaskDescription task = TaskDescription.parseFrom(data);
- jclass clazz = env->FindClass("org/apache/mesos/Protos$TaskDescription");
+ jclass clazz = FindMesosClass(env, "org/apache/mesos/Protos$TaskDescription");
jmethodID parseFrom =
env->GetStaticMethodID(clazz, "parseFrom",
@@ -185,7 +305,7 @@ jobject convert(JNIEnv* env, const TaskS
env->SetByteArrayRegion(jdata, 0, data.size(), (jbyte*) data.data());
// TaskStatus status = TaskStatus.parseFrom(data);
- jclass clazz = env->FindClass("org/apache/mesos/Protos$TaskStatus");
+ jclass clazz = FindMesosClass(env, "org/apache/mesos/Protos$TaskStatus");
jmethodID parseFrom =
env->GetStaticMethodID(clazz, "parseFrom",
@@ -208,7 +328,7 @@ jobject convert(JNIEnv* env, const Slave
env->SetByteArrayRegion(jdata, 0, data.size(), (jbyte*) data.data());
// SlaveOffer offer = SlaveOffer.parseFrom(data);
- jclass clazz = env->FindClass("org/apache/mesos/Protos$SlaveOffer");
+ jclass clazz = FindMesosClass(env, "org/apache/mesos/Protos$SlaveOffer");
jmethodID parseFrom =
env->GetStaticMethodID(clazz, "parseFrom",
@@ -231,7 +351,7 @@ jobject convert(JNIEnv* env, const Execu
env->SetByteArrayRegion(jdata, 0, data.size(), (jbyte*) data.data());
// ExecutorInfo executor = ExecutorInfo.parseFrom(data);
- jclass clazz = env->FindClass("org/apache/mesos/Protos$ExecutorInfo");
+ jclass clazz = FindMesosClass(env, "org/apache/mesos/Protos$ExecutorInfo");
jmethodID parseFrom =
env->GetStaticMethodID(clazz, "parseFrom",
@@ -254,7 +374,7 @@ jobject convert(JNIEnv* env, const Execu
env->SetByteArrayRegion(jdata, 0, data.size(), (jbyte*) data.data());
// ExecutorArgs args = ExecutorArgs.parseFrom(data);
- jclass clazz = env->FindClass("org/apache/mesos/Protos$ExecutorArgs");
+ jclass clazz = FindMesosClass(env, "org/apache/mesos/Protos$ExecutorArgs");
jmethodID parseFrom =
env->GetStaticMethodID(clazz, "parseFrom",