> The offending code is below (debug statements removed for brevity). It
> fails on the FindClass(). It seems that the class loader is not the
[quoted text clipped - 4 lines]
> 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