Servlet + JNI = remote control hardware
hi, everybody ~ HELP! HELP!
Does Someone have the example for "Servlet + JNI"?
I have a problem:
JAVA -> JNI -> C -> DLL (Control Hardware)
the DLL is OK, so I can control Hardware.
but how to use "Servlet" with "JNI" ?
does any body have examples? help~~~~
thanks..
[332 byte] By [
cofensen] at [2007-9-26 3:15:18]

I would think you could just have the doGet() or doPost() method of the servlet call your native methods that are in your Java class that goes through JNI. It really shouldn't be any different.
Hmm, thanks. I tried. ^_QBut something strange in the error message below:java.lang.NoClassDefFoundErrorat java.lang.Class.forName0(Native Method)at java.lang.Class.forName(Class.java:195)in the simple Java -> JNI -> C , it's works good.
Your class that contains the native method(s), have you put its .class file in the servlet engine's classpath, e.g. WEB-INF/classes or WEB-INF/lib?Servlet -> Java wrapper class -> native C++ methodLooks like Servlet cannot find your Java wrapper class.
yilin at 2007-6-29 11:26:28 >

Yes. I put.and something strange still in the message.I put all of the files I created. The message appears again.Any suggestion? Help~~~ thanks
Can you show the entire stack trace of that message? Can you tell from the trace which class cannot be found?
yilin at 2007-6-29 11:26:28 >

I feel so strange.I tried so much times....can't find the answer... help~~Do you have a sample for Servlet -> JNI -> C ?
So terrable... Q_Q... help
For the Servlet problem, I can't solve it.So now I am changing a way.
Using JavaBean to replace the Servlet way.
"JavaBean -> Java -> JNI -> C"
the JavaBean only doing interface for "Java".
Let JavaBean call the Java.
But the message is shown again.. my God... Q_Q
I post it in next message.
-[ JSP file ]--
<jsp:useBean id="myBean" scope="page" class="Counter"/>
<jsp:getProperty name="myBean" property="count"/>
-[ Counter.java ] for JavaBean
import HelloWorld;
public class Counter{
public Counter(){
}
public String getCount(){
HelloWorld abc = new HelloWorld();
String rr = abc.print();
return rr;
}
public void setCount(int newCount){
}
}
-[ Java -> JNI ]--
class HelloWorld {
public native String print();
public static void main(String[] args){
new HelloWorld().print();
}
static{
System.loadLibrary("HelloWorld");
}
}
[ HelloWorld.c ]
#include <jni.h>
#include <stdio.h>
#include "HelloWorld.h"
JNIEXPORT jstring JNICALL
Java_HelloWorld_print(JNIEnv *env,jobject obj){
printf("Hello World!\n hihihi success!");
return;
}
-- Server replay --
500 Internal Server Error
java.lang.NoClassDefFoundError
at Counter.getCount(Counter.java:10)
.......
What can I do.... so strange... Q_Q
So your Count cannot find HelloWorld class. How do you package them in the deployment dir? Do you have both Count.class and HelloWorld.class in the same jar file? If they are not in jar files, are the 2 class files in the same dir?
yilin at 2007-6-29 11:26:28 >

Yes, they all in the same dir.
I tried so much ways , but still can't success.
Now I Combine the JavaBean and (Java->JNI) in the it.
*** Counter.java (JavaBean) , Compiler OK, in DOS see the words from calling C's DLL. Because I have main().
public class Counter{
public Counter(){}
public native String printt();
public static void main(String[] args){
new Counter().printt();
}
public String getCount(){
return(new Counter().printt());
}
public void setCount(int newCount){}
static{
System.loadLibrary("HelloWorld");
}
}
*** HelloWorld.c *****
class HelloWorld {
public native String printt();
public static void main(String[] args){
new HelloWorld().printt();
}
static{ System.loadLibrary("HelloWorld"); }
}
************* The result that Server says ******
500 Internal Server Error
java.lang.NoClassDefFoundError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:195)
at com.evermind.server.http.HttpApplication.v6(JAX)
.....
I think use JavaBens is easy to decrease the level of calling much methods. And it can use in the JSP.
BUT... Why appear the "forName0" and "forName" this two guys? My God...help~~~ thanks Q_Q
Can you check if the "PATH" env variable for you server includes the dir containing your dll file (HelloWorld.dll)? Usually when you start the server, the start script set "PATH" for the server. (If you use Unix, it's LD_LIBRARY_PATH instead of PATH.)
yilin at 2007-6-29 11:26:28 >

the server can find the HelloWorld.dll,if not, will show the loading dll file error...so... strange.... (ps. my OS is W2k... )help~~~
at com.evermind.server.http.HttpApplication.v6(JAX)
I am trying to verify exactly which class it is not finding. To do this, I need to locacte the exactly souce code line that cause this exception. So can you show the entire stack trace following the above line? And tell me which line is the 1st line that shows YOUR source code? (I guess com.evermind... is your server vendor, not your own source package, right?)
yilin at 2007-6-29 11:26:28 >

hmm.. if the 1st and 2nd error lines can solve , then others error lines should not be shown.They are continue errors, like the 1st error can solve, it may not be shown at 2nd error.thanks..
Thanks you again... ^_^ to help me more times..
All My step and files are shown below:
--[1 step]--[ JSP file ]--
<jsp:useBean id="myBean" scope="page" class="Counter"/>
<jsp:getProperty name="myBean" property="count"/>
--[2 step][ write JavaBean ]--
public class Counter{
public Counter(){}
public native String printt();// It's Native entry
public static void main(String[] args){ // This just for Java in DOS runable.
new Counter().printt();
}
public String getCount(){
return(new Counter().printt());
@@@@@@@@@@@@@@@@ <= the server will call getCount() method, which the DLL's create the printt() method.it may cause the 1st errors because can't find printt().I guess.
}
public void setCount(int newCount){}
static{
System.loadLibrary("HelloWorld"); //LOAD the DLL's from C create
}
}
[3 step] [ Create Counter.h ] -- CMD:[ javah - jni Counter ]
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Counter */
#ifndef _Included_Counter
#define _Included_Counter
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class:Counter
* Method:printt
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_Counter_printt
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
-[4 step] [Write HelloWorld.c ]-
#include <jni.h>
#include <stdio.h>
#include "Counter.h"
JNIEXPORT jstring JNICALL
Java_Counter_printt(JNIEnv *env,jobject this){
printf("Hello World!\n hihihi success!");
return;
}
[5 step]-- [use VC++ 5 to create the DLL from HelloWorld.c ]
[6 step] -- The result that Server says -
500 Internal Server Error
java.lang.NoClassDefFoundError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:195)
...
To top of stack trace is usually system calls, but these calls can be traced back to your OWN source code, which shows up in the MIDDLE of the stack. So you need to look down to the MIDDLE of the stack trace to find the very first line mentioning your OWN source code. You see what I mean?
yilin at 2007-7-1 3:34:56 >

Understand...nothing.... ?_Q"Could you show a simple sample?THANKS YOU AGAIN~~ ^_^[Before] I had writen a Servlet + JNI, only let the JNI in the Servlet, and then I got the same error 2 lines.
500 Internal Server Error
java.lang.NoClassDefFoundError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:195)
...
In your above posting, why don't you show the entire stack trace instead of "..."? Those "..." may turn out to have important information. That's all I mean.
yilin at 2007-7-1 3:34:56 >

Because when error appears.
the error line (I mean "....." is the chain reaction of errors.
if I can solve the front of the two errors. then the error will disapper.
thanks for your help. ^_Q"
I show the all error messages below.
--
500 Internal Server Error
java.lang.NoClassDefFoundError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at com.evermind.server.http.HttpApplication.v6(JAX)
at com.evermind.server.http.ei.tx(JAX)
at com.evermind.server.http.ei.s_(JAX)
at com.evermind.server.http.JSPPage.s_(JAX)
at com.evermind.server.http.HttpApplication.wh(JAX)
at com.evermind.server.http.HttpApplication.xj(JAX)
at com.evermind.server.http.JSPServlet.service(JAX)
at com.evermind.server.http.ea.doFilter(JAX)
at com.orionsupport.cocoon.CocoonFilter.doFilter(CocoonFilter.java:65)
at com.evermind.server.http.d3.sw(JAX)
at com.evermind.server.http.d3.su(JAX)
at com.evermind.server.http.ef.s1(JAX)
at com.evermind.server.http.ef.do(JAX)
at com.evermind.util.f.run(JAX)
It seems that your server cannot find your Servlet/JSP class, because the stack trace does not contain any of your own code, so your JSP is not even run yet.
Try this: put a very simple JSP without any native stuff, just output an HTML string, see it your server can get to your JSP or not.
yilin at 2007-7-1 3:34:56 >

Thanks for your suggestion.
But I used the server a long time ago.
The JSP page is good for run, not the server can't find my JSP page.
I guess the error is the server can't find the "method loaded from DLL file."
So will cause a chain error lines. not for the JSP page can't be founded.
HELP~~~
I solve all the problem~thanks for help me programming thinking ways past this months. ^_^
Curious what the problem(s) really turned out to be?
yilin at 2007-7-1 3:34:56 >

Hi cofensen ! I read the problem you have had, is the same or similar i have. Can you tell me how you put it to work ?Thanks in advance!
Hi Cofensen,
Use try-catch blocks in your code.
Use a try catch block like this.
Where the error could possibly occur.
If you dont want to use try catch block here and there, then declare the method to throws Exception.
This will give the complete stacktrace.
Safe code
try
{
Any unsafe code
Native method calling code
}
catch(Exception)
{
print trace
}
catch(Throwable t)
{
print stack trace
}
Because if you dont catch an error ,
then you give the burden to your webServer.
By the way can you please mention your webserver and
give details about how you have deployed in that.
Some java program should run in the webserver.
check whether the DLL is there in the "-Djava.library.path=<Path of Dir of the dll in server>"
We could solve it. Dont worry.
Good Luck.
Hi cofensen,Good you solved the problem. I have the same problem... Could you please tell us how you solved it ? steps / sample code .. that would help lot of people like me on this forum.ThanksRam
I'm pretty sure it's ClassLoader. Classes loaded from different 'classloaders' do not 'see' each other (i recall first versions of ServletExec were really weird because of that). So, there is a big chance that from wherever you are calling the native methods from, this class has been loaded in different class loader (i'm not that good in servlet engine specifications, but again, that old ServletExec engine explicitely pointed out that you can not refer to the _static_ field of your HttpServlet class between the calls, since the value is not guaranteed to stay the same, which means that HttpServlet classes can be loaded from different class loaders).
I didn't read all the code you've been sending, but my hunch would be to declare the native methods in a separate class (_not_ HttpServlet). This is so called 'services' class shared between servlets (again, in some early engines you should had put this classes in a separate directory, aside from servlets - i guess for exactly the same reason - they were loaded in a separate classloader so that 'servlet' class loaders could access it).
public class MyServlet extends HttpServlet {
public void doGet(req, resp) {
NativeService.getService().runMethod();
}
}
public class NativeService {
static NativeService ns = new NativeService();
private NativeService() {}
public native runMethod();
public NativeService getService() {return ns;}
}
