Content received from: http://JavaFAQ.nu/java-article1027.html
Ready Java example: Embed JVM into native code. Monday, August 14, 2006 (00:00:00)
Posted by Javaaddict
Today we added a collection of sample JNI (Java Native Interace) programs. The ideas are mostly taken from the Sun Java tutorial.
EmbeddingJVM : This code sample illustrates how to embed and call the JVM from a native program.
| Code: |
/* JNIEmbed.c */
/**
* Invoking the Java Virtual Machine
* ---------------------------------
*
* The JDK ships the Java Virtual Machine as a shared library
* (or dynamic link library on Win32). You can embed the Java
* Virtual Machine into your native application by linking
* the native application with the shared library.
*
* The JNI supports an Invocation API that allows you to load,
* initialize, and invoke the Java Virtual Machine. Indeed,
* the normal way of starting the Java interpreter, java, is
* no more than a simple C program that parses the command line
* arguments and invokes the Java Virtual Machine through the
* Invocation API.
*
* This program is an implementation of the lessons in the Sun
* Java Tutorial. Though it will require only minor changes to
* run this on multiple platforms, currently this has been
* developed and tested on Windows 2000.
*
* Author: Tanmay K. M.
* http://tanmaykm.tripod.com/
*/
#include <stdio.h>
#include <windows.h>
#include <process.h>
#include <jni.h>
/*
Include jni.h for JNI specific methods. This header file can
be found in the JDK include directory. Include the path to
the JNI include directories in your project make file.
For example:
If you have JDK 1.3.1 installed in C:\ directory, include
the following two directories:
C:\jdk1.3.1\include
C:\jdk1.3.1\include\win32
In addition you must link your executable to the jvm.lib
library and add the path to the jvm.dll to your PATH or
LD_LIBRARY_PATH environment variable to enable the exe
to load the JVM.
Compile a Java class with main (an example java file is
provided:
public class JNIEmbedTest
{
public static void main(String [] args)
{
System.out.println("Hello from JNIEmbedTest");
System.out.println("String from C: " + args[0]);
}
}
Place both the executable and the class file in the same
directory and execute the executable with the Java class
file name as the argument.
*/
/* The path where the class file being executed can be found */
#define USER_CLASSPATH "."
#define USER_LIBPATH "."
/*
The following structure is used to pass data from the
main thread to worker threads. The usage of this will
become clear later in the program.
*/
typedef struct threadData
{
JNIEnv *env;
JavaVM *jvm;
char *sClassName;
int iThreadIndex;
} tstThreadData;
/**
* CallMain
*
* Calls the main method of a class file.
* Passes the string "Hello World frm C!" to the Java
* class as the argument to the main method.
*/
int CallMain(JNIEnv *env, JavaVM *jvm, const char *sClassName)
{
jclass cls;
jmethodID mid;
jstring jstr;
jobjectArray args;
/* locate and load the class file */
if ((cls = (*env)->FindClass(env, sClassName)) == 0)
{
fprintf(stderr, "Can't find class %s\n", sClassName);
return -1;
}
/* locate the main method */
if ((mid = (*env)->GetStaticMethodID(env, cls, "main", "([Ljava/lang/String;)V")) == 0)
{
fprintf(stderr, "Can't find main method in class %s\n", sClassName);
return -1;
}
/* create a new java string to be passes to the class */
if ((jstr = (*env)->NewStringUTF(env, "Hello World from C!")) == 0)
{
fprintf(stderr, "Out of memory\n");
return -1;
}
/* create a new string array with a single element containing the
string created above */
args = (*env)->NewObjectArray(env, 1, (*env)->FindClass(env, "java/lang/String"), jstr);
if (args == 0)
{
fprintf(stderr, "Out of memory\n");
return -1;
}
/* call the main method with the required arguments */
(*env)->CallStaticVoidMethod(env, cls, mid, args);
return 0;
}
/**
* CallMainInThread
*
* Calls the main method of the class file inside a worker
* thread created in C. This involves attaching the native
* thread to the JVM and involing the main method in the thread.
*/
int CallMainInThread(JNIEnv *env, JavaVM *jvm, const char *sClassName, int threadNum)
{
jint res;
/* attach the current native thread created in C to the JVM */
/* pass NULL as the third argument */
res = (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
if (res < 0)
{
fprintf(stderr, "Thread %d: attach failed\n", threadNum);
return -1;
}
printf("Thread %d running\n", threadNum);
/* call the main method. the method will now be called in the
context of the C thread, which has now been attached to the JVM */
CallMain(env, jvm, sClassName);
/* print out any exceptions that might have occured in Java */
/* It is extremely important to check, handle, and clear the pending
exception before calling subsequent JNI functions. Calling arbitrary
JNI functions with a pending exception may lead to unexpected results.
You can safely call only a small number of JNI functions when there
is a pending exception. These functions are ExceptionOccurred,
ExceptionDescribe, and ExceptionClear.
*/
if ((*env)->ExceptionOccurred(env))
{
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}
/* detach the current thread from the JVM. */
(*jvm)->DetachCurrentThread(jvm);
return 0;
}
/**
* TestThread
*
* This method is the entry point for the C thread. The argument it
* receives is an instance of the structure of type tstThreadData.
* It extracts the relevant stuff from the structure and calls the
* method CallMainInThread to actually attach the thread to the JVM
* and call the Java class.
*/
void TestThread(void *args)
{
tstThreadData *pThreadData = (tstThreadData *)args;
CallMainInThread(pThreadData->env, pThreadData->jvm, pThreadData->sClassName, pThreadData->iThreadIndex);
_endthread();
}
/**
* The main method.
* Creates the JVM. Calls the Java class in both threaded and
* non-threaded manner
*/
int main(int argc, char **argv)
{
JNIEnv *env;
JavaVM *jvm;
JavaVMInitArgs vm_args;
JavaVMOption options[4];
jint res;
int iThreadIndex;
tstThreadData *pThreadData;
/* IMPORTANT: specify vm_args version # if you use JDK1.1.2 and beyond */
vm_args.version = JNI_VERSION_1_2;
vm_args.nOptions = 0;
options[0].optionString = "-Djava.compiler=NONE"; /* disable JIT */
options[1].optionString = "-Djava.class.path=" USER_CLASSPATH; /* user classes */
options[2].optionString = "-Djava.library.path=" USER_LIBPATH; /* set native library path */
options[3].optionString = "-verbose:jni"; /* print JNI-related messages */
if(1 == argc)
{
fprintf(stderr, "Usage: %s <main class name>\n", argv[0]);
exit(1);
}
printf("Running class %s.\n", argv[0]);
printf("After the program is finished, press ENTER to terminate the JVM.\n");
/* Create the Java VM */
if ((res = JNI_CreateJavaVM(&jvm,(void **)&env,&vm_args)) < 0)
{
fprintf(stderr, "Can't create Java VM\n");
exit(1);
}
/* call the main method of the Java class from the main thread */
CallMain(env, jvm, argv[1]);
/* Create 5 threads and call the Java class from the threads */
pThreadData = malloc(5 * sizeof(tstThreadData));
for (iThreadIndex=0; iThreadIndex<5; iThreadIndex++)
{
tstThreadData *pThisThreadData = pThreadData + iThreadIndex;
pThisThreadData->env = env;
pThisThreadData->jvm = jvm;
pThisThreadData->sClassName = argv[1];
pThisThreadData->iThreadIndex = iThreadIndex;
/* We pass the thread number as the argument to every thread */
_beginthread(TestThread, 0, (void *)pThisThreadData);
}
getchar();
free(pThreadData);
/* destroy the JVM */
(*jvm)->DestroyJavaVM(jvm);
return 0;
}
|
| Code: |
/* JNIEmbedTest.java
This is a sample program for use with JNIEmbed.c.
After compiling JNIEmbed, you can invoke JNIEmbed
with this class as the parameter.
*/
public class JNIEmbedTest
{
public static void main(String [] args)
{
System.out.println("Hello from JNIEmbedTest");
System.out.println("String from C: " + args[0]);
}
}
|
|