2009-08-10 09:10:31 UTC
You were right with your analysis.
The problem is the point of binding the Java Class. It is bound the first time the callback is called and therefore attached to the OSGi Thread which has no reference to the class of JNotify. I Modified the code to run in an OSGi container as follow (modified parts):
File: net_contentobjects_jnotify_win32_JNotify_win32.cpp
Field-Descriptions:
Win32FSHook *_win32FSHook;
enum INIT_STATE
{
NOT_INITIALIZED,
PRE_INITIALIZED,
INITIALIZED,
FAILED
}
_initialized = NOT_INITIALIZED;
static JavaVM *_jvm = 0;
static jmethodID _mid;
static jclass _clazz;
static JNIEnv* _env;
Method: ChangeCallbackImpl
if(_initialized == NOT_INITIALIZED || _initialized == FAILED)
{
return;
}
if(_initialized == PRE_INITIALIZED)
{
// attach daemon thread to running JVM once
_jvm->AttachCurrentThreadAsDaemon((void**)&_env, NULL);
_initialized = INITIALIZED;
}
jstring jRootPath = _env->NewString((jchar*)rootPath, wcslen(rootPath));
jstring jFilePath = _env->NewString((jchar*)filePath, wcslen(filePath));
_env->CallStaticVoidMethod(_clazz, _mid, watchID, action, jRootPath, jFilePath);
Method nativeInit:
if(_initialized != NOT_INITIALIZED){
log("nativeInit called more than once");
return 0;
}
try
{
// initialize Java Runtime components
if(_jvm == NULL){
log("JVM is NULL");
throw -1;
}
_env = env;
if(_env == NULL){
log("JNI Environment is NULL");
throw -1;
}
char className[] = "net/contentobjects/jnotify/win32/JNotify_win32";
_clazz = _env->FindClass(className);
if(_clazz == NULL){
log("could not find net/contentobjects/jnotify/win32/JNotify_win32 in JNI env");
throw -1;
}
_mid = _env->GetStaticMethodID(_clazz, "callbackProcessEvent", "(IILjava/lang/String;Ljava/lang/String;)V");
if(_mid == NULL){
log("could not find static method callbackProcessEvent in class net/contentobjects/jnotify/win32/JNotify_win32");
throw -1;
}
_win32FSHook = new Win32FSHook();
_win32FSHook->init(&ChangeCallbackImpl);
_initialized = PRE_INITIALIZED;
return 0;
}
catch (int err)
{
_initialized = FAILED;
return err;
}
What is done here is to store a reference to JNIEnv within nativeInit to have a reference to the ClassLoader holding the Jnotify Classes.