Contents | Prev | Next

The Invocation API


5

The Invocation API allows software vendors to load the Java VM into an arbitrary native application. Vendors can deliver Java-enabled applications without having to link with the Java VM source code.

This chapter begins with an overview of the Invocation API. This is followed by reference pages for all Invocation API functions.

Overview

Code Example 5-1 illustrates using functions in the Invocation API. In this example, the C++ code creates a Java VM and invokes a static method, called Main.test. For clarity, we omit error checking.

Code Example 5-1 Using the Invocation API in C++

#include <jni.h>       /* where everything is defined */

...

JavaVM *jvm;       /* denotes a Java VM */
JNIEnv *env;       /* pointer to native method interface */

JavaVMInitArgs vm_args;        /* VM initialization arguments */

/* The default arguments are usually good enough. */
JNI_GetDefaultJavaVMInitArgs(&vm_args);

/* load and initialize a Java VM, return a native method interface 
 * pointer in env */
JNI_CreateJavaVM(&jvm, &env, &vm_args);

/* invoke the Main.test method using the JNI */
jclass cls = env->FindClass("Main");
jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V");
env->CallStaticVoidMethod(cls, mid, 100);

/* We are done. */
jvm->DestroyJavaVM();

Code Example 5-1 uses three functions in the API. The Invocation API allows a native application to use the JNI interface pointer to access VM features. The design is similar to Netscape's JRI Embedding Interface.

Creating the VM

The JNI_CreateJavaVM() function loads and initializes a Java VM and returns a pointer to the JNI interface pointer. The thread that called JNI_CreateJavaVM() is considered to be the main thread.

Attaching to the VM

The JNI interface pointer (JNIEnv) is valid only in the current thread. Should another thread want to access the Java VM, it must first call AttachCurrentThread() to attach itself to the VM and to obtain a JNI interface pointer. Once attached to the VM, a native thread works just like an ordinary Java thread running inside a native method. The native thread remains attached to the VM until it calls DetachCurrentThread() to detach itself.

Unloading the VM

The main thread cannot detach itself from the VM. Instead, it must call DestroyJavaVM() to unload the entire VM. In addition, the main thread is the only thread that can unload the VM.

The main thread must be the only user thread running in the Java VM when it calls the DestroyJavaVM() function to unload the Java VM. User threads include both Java threads and attached native threads. This restriction exists because a Java thread or attached native thread may be holding system resources, such as locks, windows, and so on. The DestroyJavaVM() function cannot automatically free these resources. By restricting the main thread to be the only running thread when the VM is unloaded, the burden of releasing system resources held by arbitrary threads is on the programmer.

Initialization Structures

Because Java VMs may use different implementation schemes, they will likely require different initialization structures. Thus, the exact content of the following initialization structures will vary among different Java VMs. A native application must correctly set the initialization structure depending on the particular VM the application wishes to invoke.

Code Example 5-2 shows the structure used to initialize the Java VM in JDK 1.1.

Code Example 5-2 Initialization Structure for Java VM in JDK 1.1

#define JDK1_1 /* a macro for conditional compilation */

typedef struct JavaVMInitArgs {
  /* 
   * whether asynchronous GC is allowed. 
   */
  int disableAsyncGC;
  /* 
   * whether GC messages will appear. 
   */
  int enableVerboseGC;
  /* 
   * whether to check the Java source files are newer than compiled
   * class files.
   */
  int checkSource;
  /*
   * maximum native stack size of Java-created threads.
   */ 
  long nativeStackSize;   
  /* 
   * maximum Java stack size.
   */
  long javaStackSize;
  /*
   * initial heap size
   */
  long minHeapSize;
  /*
   * maximum heap size
   */
  long maxHeapSize;
  /*
   * controls whether Java byte code should be verified:
   * 0 -- none, 1 -- remotely loaded code, 2 -- all code.
   */
  int verifyMode;
  /*
   * the local directory path for class loading
   */
  const char *classpath;
} JavaVMInitArgs;

Code Example 5-3 provides the arguments needed when a native thread attaches to a Java VM in JDK 1.1. In actuality, no arguments are required for a native thread to attach to the JDK 1.1. The ThreadAttachArgs structure only includes a padding slot for C compilers that do not permit empty structures.

Code Example 5-3 Arguments for Native Thread to Attach to VM in JDK 1.1

typedef struct ThreadAttachArgs {
  /*
   * JDK 1.1 does not need any arguments to attach a
   * native thread. The padding is here to satisfy the C
   * compiler which does not permit empty structures.
   */
   void *__padding;
}  ThreadAttachArgs;

Invocation API Functions

The JavaVM type is a pointer to the Invocation API function table. Code Example 5-4 shows this function table:

Code Example 5-4 Invocation API Function Table

typedef const struct JNIInvokeInterface *JavaVM;

const struct JNIInvokeInterface ... = {
    NULL,
    NULL,
    NULL,

    DestroyJavaVM,
    AttachCurrentThread,
    DetachCurrentThread,
};

Note that three Invocation API functions, JNI_GetDefaultJavaVMInitArgs(), JNI_GetCreatedJavaVMs(), and JNI_CreateJavaVM(), are not part of the JavaVM function table. These functions can be used without a preexisting JavaVM structure.

JNI_GetDefaultJavaVMInitArgs

void JNI_GetDefaultJavaVMInitArgs(
JavaVMInitArgs *vm_args);

Returns a default configuration for the Java VM.

PARAMETERS:

vm_args: a pointer to a JavaVMInitArgs structure in which the default arguments will be filled in.

JNI_GetCreatedJavaVMs

jint JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen,
jsize *nVMs);

Returns all Java VMs that have been created. Pointers to VMs are written in the buffer vmBuf in the order they are created. At most bufLen number of entries will be written. The total number of created VMs is returned in *nVMs.

JDK 1.1 does not support creating more than one VM in a single process.

PARAMETERS:

vmBuf: pointer to the buffer where the VM structures will be placed.

bufLen: the length of the buffer.

nVMs: a pointer to an integer.

RETURNS:

Returns zero on success; otherwise, returns a negative number on failure.

JNI_CreateJavaVM

jint JNI_CreateJavaVM(JavaVM **p_vm, JNIEnv **p_env,
JavaVMInitArgs *vm_args);

Loads and initializes a Java VM. The current thread becomes the main thread. Sets the env argument to the JNI interface pointer of the main thread.

JDK 1.1 does not support creating more than one VM in a single process.

PARAMETERS:

p_vm: pointer to the location where the resulting VM structure will be placed.

p_env: pointer to the location where the JNI interface pointer for the main thread will be placed.

vm_args: Java VM initialization arguments.

RETURNS:

Returns zero on success; otherwise, returns a negative number on failure.

DestroyJavaVM

jint DestroyJavaVM(JavaVM *vm);

Unloads a Java VM and reclaims its resources. Only the main thread can unload the VM. The main thread must be the only remaining user thread when it calls DestroyJavaVM().

PARAMETERS:

vm: the Java VM that will be destroyed.

RETURNS:

Returns zero on success; otherwise, returns a negative number on failure.

JDK 1.1 does not support unloading the VM.

AttachCurrentThread

jint AttachCurrentThread(JavaVM *vm, JNIEnv **p_env,
ThreadAttachArgs *thr_args);

Attaches the current thread to a Java VM. Returns a JNI interface pointer in the JNIEnv argument.

Trying to attach a thread that is already attached is a no-op.

A native thread cannot be attached simultaneously to two Java VMs.

PARAMETERS:

vm: the VM to which the current thread will be attached.

p_env: pointer to the location where the JNI interface pointer of the current thread will be placed.

thr_args: the thread attachment arguments.

RETURNS:

Returns zero on success; otherwise, returns a negative number on failure.

DetachCurrentThread

jint DetachCurrentThread(JavaVM *vm);

Detaches the current thread from a Java VM. All Java monitors held by this thread are released. All Java threads waiting for this thread to die are notified.

The main thread, which is the thread that created the Java VM, cannot be detached from the VM. Instead, the main thread must call JNI_DestroyJavaVM() to unload the entire VM.

PARAMETERS:

vm: the VM from which the current thread will be detached.

RETURNS:

Returns zero on success; otherwise, returns a negative number on failure.


Contents | Prev | Next

Java Native Method Interface Specification (HTML generated by wegis on December 06, 1996)
Copyright © 1996 Sun Microsystems, Inc. All rights reserved
Please send any comments or corrections to sl@eng.sun.com