JNI callback from Tomcat using FindClass

Discussion in 'Java' started by colm.dougan@gmail.com, Feb 23, 2006.

  1. Guest

    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;
    }
     
    , Feb 23, 2006
    #1
    1. Advertising

  2. Chris Uppal Guest

    wrote:

    > 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.


    It's difficult to be sure what's going on here. I think it depends on things
    like how you use C++ threads, when callbacks are invoked, and perhaps even on
    where your .classfiles are kept :-(

    Here's how I understand it.

    FindClass() uses the classloader of the Java code where the currently executing
    native method is defined. It not clear from the spec what happens in other
    cases, but I /assume/ that you are in JNI code because you are using the
    invocation API (not the case for your application) then it'll use the system
    classloader. I also assume (which may be relevant -- see below) that when the
    DLL (or equivalent) is initialised (the JNI_OnLoad() handler function in the
    DLL) that FindClass() will use the classloader of the class which is calling
    System.loadLibrary(). Lastly, I assume that if a C++ thread (i.e. started from
    C++ and calling AttachCurrentThread(), rather than from Java code), uses
    FindClass() then that will use the system classloader.

    NB: all the above assumptions are /only/ assumptions -- i.e. I don't know for
    sure (although they seem reasonable).

    So, which classloader will be used depends on which code looks for it. (Nice
    and simple isn't it ;-). From your code snippet it appears that you are using
    independent C++ threads, which might be one source of your problems. If you
    are, then I suggest either doing the FindClass() in the DLL's JNI_OnLoad(), or
    in some native method which is used to initialise your sub-system (if there is
    one). You would then have to cache a global reference to it (as you have
    already tried). Other than that, I don't see a problem with invoking
    callbacks from off-thread (assuming the code is correct).

    Possibly the change in Tomcat versions causes a difference in the
    initialisation order, or something similar so that the FindClass() happens in a
    different context -- but that's pure guesswork.

    OTOH, if your JNI code is invoked from Java, so that the callbacks are just
    calls back "up the stack" as it were, then I don't see why you should be having
    problems at all, so maybe the problem is caused by something else entirely.

    Another issue which may be relevant (probably not, but I'll mention it anyway),
    is that JNI will only load each DLL for one classloader. So if you have
    multiple applications under Tomcat which use the "same" class (and its native
    code) then you /have/ to put that class in the shared classes area. You can't
    have native code duplicated in two applications, it has to be shared.

    -- chris
     
    Chris Uppal, Feb 24, 2006
    #2
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Steve
    Replies:
    3
    Views:
    26,261
    Mark Buckingham
    Dec 31, 2003
  2. FBergemann
    Replies:
    3
    Views:
    7,694
    FBergemann
    Apr 6, 2005
  3. Replies:
    2
    Views:
    1,795
  4. maverick
    Replies:
    4
    Views:
    1,129
    Chris Uppal
    Jul 18, 2006
  5. Praetorian

    JNI FindClass problem

    Praetorian, Jul 9, 2009, in forum: Java
    Replies:
    3
    Views:
    1,886
    Roedy Green
    Jul 9, 2009
Loading...

Share This Page