C
colm.dougan
Hi,
I've inherited some code that uses JNI from Tomcat to call down to C to
initialise/subscribe to some messaging with a callback the other way (C
to Java) when a message is going to be passed back up to Java. This
used to work fine but a change of platform (slightly older Tomcat/4.1
than befoe, upgrade to latest Java 1.4.2 from 1.4.0) it has stopped
working.
The offending code is below (debug statements removed for brevity). It
fails on the FindClass(). It seems that the class loader is not the
one it expects to have. It seems to be assumed that the tomcat
classloader will be used but this doesn't seem to be the case. I have
been reading various internet knowdlege bases that imply that FindClass
will use the system/boot class loader and so this shouldn't work at
all. But how could it ever have worked? Was it previously relying on
bugs? Or is this a reasonable thing to do as the VM is kept attached.
I tried some things suggested on various sites/groups to hold a pointer
to the jobject initially passed down from Java to C in the native
method using env->NewGlobalRef(jobj); When I used the jobj later it
either crashed my tomcat or the GetStaticMethodID returned 0. I'm
aware there may be threading issues with that approach.
Any advice? I'm primarily interested in what the "right thing" is to
do here because it is not clear to me and I'm new to JNI. Is this even
the rigtht what to do callbacks of this type?
Thanks,
Colm
// a static instance of this class is held globally
// ...
int CommJNIHandler::setupThread( JNIEnv **env )
{
// JavaVM *m_pjVM is a private member variable
int rv = m_pjVM->GetEnv((void**)env, JNI_VERSION_1_2 );
if ( rv != JNI_OK )
{
if ( m_pjVM->AttachCurrentThread((void**)env, NULL) != 0 )
return -1;
}
return 0;
}
int CommJNIHandler::doCallBack ( int pMsgData ) {
JNIEnv *env;
if ( setupThread( &env ) != 0 )
{
return -1;
}
jclass cls = env->FindClass("COM/name/of/class");
if (env->ExceptionOccurred()) {
env->ExceptionDescribe();
return -1;
}
jmethodID mid = env->GetStaticMethodID(
cls, "executeMessageHandlerFromNative", "(I)I" );
if ( mid == 0 )
{
return -1;
}
int nRet = env->CallStaticIntMethod( cls, mid, (jint)pMsgData );
if ( env->ExceptionOccurred() )
{
env->ExceptionDescribe();
env->ExceptionClear();
}
return nRet;
}
I've inherited some code that uses JNI from Tomcat to call down to C to
initialise/subscribe to some messaging with a callback the other way (C
to Java) when a message is going to be passed back up to Java. This
used to work fine but a change of platform (slightly older Tomcat/4.1
than befoe, upgrade to latest Java 1.4.2 from 1.4.0) it has stopped
working.
The offending code is below (debug statements removed for brevity). It
fails on the FindClass(). It seems that the class loader is not the
one it expects to have. It seems to be assumed that the tomcat
classloader will be used but this doesn't seem to be the case. I have
been reading various internet knowdlege bases that imply that FindClass
will use the system/boot class loader and so this shouldn't work at
all. But how could it ever have worked? Was it previously relying on
bugs? Or is this a reasonable thing to do as the VM is kept attached.
I tried some things suggested on various sites/groups to hold a pointer
to the jobject initially passed down from Java to C in the native
method using env->NewGlobalRef(jobj); When I used the jobj later it
either crashed my tomcat or the GetStaticMethodID returned 0. I'm
aware there may be threading issues with that approach.
Any advice? I'm primarily interested in what the "right thing" is to
do here because it is not clear to me and I'm new to JNI. Is this even
the rigtht what to do callbacks of this type?
Thanks,
Colm
// a static instance of this class is held globally
// ...
int CommJNIHandler::setupThread( JNIEnv **env )
{
// JavaVM *m_pjVM is a private member variable
int rv = m_pjVM->GetEnv((void**)env, JNI_VERSION_1_2 );
if ( rv != JNI_OK )
{
if ( m_pjVM->AttachCurrentThread((void**)env, NULL) != 0 )
return -1;
}
return 0;
}
int CommJNIHandler::doCallBack ( int pMsgData ) {
JNIEnv *env;
if ( setupThread( &env ) != 0 )
{
return -1;
}
jclass cls = env->FindClass("COM/name/of/class");
if (env->ExceptionOccurred()) {
env->ExceptionDescribe();
return -1;
}
jmethodID mid = env->GetStaticMethodID(
cls, "executeMessageHandlerFromNative", "(I)I" );
if ( mid == 0 )
{
return -1;
}
int nRet = env->CallStaticIntMethod( cls, mid, (jint)pMsgData );
if ( env->ExceptionOccurred() )
{
env->ExceptionDescribe();
env->ExceptionClear();
}
return nRet;
}