In this chapter you'll learn how to access native C code from Java. You will see how to use the supplied tools to create a dynamic link library (DLL), which the Java runtime interpreter can call to perform native functions. When you finish this chapter, you will be able to link your Java code with native C methods.
However, regardless of the reason, there might always be a need to access the raw speed or other platform-specific facilities. To accommodate this need, Java provides access to native code stored in dynamic link libraries.
When Java code is executed on a machine other than a native Java microprocessor, a runtime interpreter is needed. The interpreter is actually the program that executes the Java code. So to allow the Java code access to native methods, the interpreter must act as the go-between for the two platforms. This is achieved by standard entry points defined in native DLLs.
The next step in calling a native method is to declare the method:
After the method has been declared, it can be called using Java's normal calling conventions. That's it from Java's standpoint. The rest of the work involves the creation of the DLL.
Shipped with the Java Developer's Kit is a utility called javah, which is designed to create the interface with which the Java runtime interpreter can communicate. It accomplishes this by taking as a parameter the class file containing the native call. javah then produces a header file, and an associated C file is needed. The process to create a header and stub C file for the calcTC class are as follows.
Execute javah to create the header file:
The final step in creating the native DLL interface is to create a stub file containing some of the needed interface overhead. To create this stub file for the calcTC class, execute the following command:
Using Native Methods
The Java programming language has gone to great lengths to hide machine-specific facilities from the programmer.However, regardless of the reason, there might always be a need to access the raw speed or other platform-specific facilities. To accommodate this need, Java provides access to native code stored in dynamic link libraries.
When Java code is executed on a machine other than a native Java microprocessor, a runtime interpreter is needed. The interpreter is actually the program that executes the Java code. So to allow the Java code access to native methods, the interpreter must act as the go-between for the two platforms. This is achieved by standard entry points defined in native DLLs.
How Native Methods Are Called
In the big picture of accessing native methods, calling native methods from Java is one of the most straightforward processes. The task of calling the native method can be broken down into three steps, all of which need to be implemented in order for the native call to work:- Loading the library
- Declaring the method
- Calling the method
import java.lang.Runtime;It is usually a good idea to call the loadLibrary method during the static initialization. This way the library is loaded before there's any chance of the method being called. If the loadLibrary method is unsuccessful, it will throw the UnsatisfiedLinkError exception. This provides a mechanism to replace the native method call.
public class calcTC //Calculates the two's
{ //complement of a passed number.
Static
{
try
{
loadLibrary("nativeDLL");
}
catch(Exception e)
{
//Do Something here
}
}
public native int twos(int number);
}
The next step in calling a native method is to declare the method:
public native int twos(int number);The native directive tells the compiler that this method is natively implemented. Besides the native directive, the method resembles a normal method declaration, except for the fact that code does not follow the declaration.
After the method has been declared, it can be called using Java's normal calling conventions. That's it from Java's standpoint. The rest of the work involves the creation of the DLL.
How Native Methods Are Created
As mentioned before, the Java runtime interpreter acts as the go-between for the Java code and the native DLL. In order to facilitate this communication, a common interface is needed.Shipped with the Java Developer's Kit is a utility called javah, which is designed to create the interface with which the Java runtime interpreter can communicate. It accomplishes this by taking as a parameter the class file containing the native call. javah then produces a header file, and an associated C file is needed. The process to create a header and stub C file for the calcTC class are as follows.
Execute javah to create the header file:
javah calcTCThis command creates a file under the cclassHeaders directory named calcTC.h. This file contains the following header information:
/* Header for class calcTC */This file declares the interface with which the Java runtime interpreter can communicate.
#ifndef _Include_calcTC
#define _Include_calcTC
typedef struct ClasscalcTC{
int number;
} ClasscalcTC;
HandleTo(calcTc);
#ifdef __cplusplus
extern "C" __declspec(dllexport)
#endif
int clacTC_twos(struct HcalcTC *,int);
#endif
The final step in creating the native DLL interface is to create a stub file containing some of the needed interface overhead. To create this stub file for the calcTC class, execute the following command:
javah -stubs calcTCThis creates the file calcTC.stubs in the subs subdirectory, which contains the following information:
/* Stubs for class calcTC */calcTC.stubs, along with stubsPreamble.h (found in the /hotjava/include subdirectory), must preface the actual implementation of the native method. That is, you must include stubsPreamble.h and the header file created by the javah command. After the include statements, insert the contents of the stub file and the native method definition. For example, the code for the calcTC native DLL would be the following:
/* DO NOT EDIT THIS FILE - it is machine generated*/
/* SYMBOL: "calcTC\twos(I)I", calcTC_twos_stub,*/
_declspec(dllexport) stack_item
*calcTC_twos_stub(stack_item *_P_,struct execenv *_EE_)
{
extern int clacTC_twos(void *,int);
_P_[0].i = calcTC_twos(_P_[0].p,((_P_[1].i)));
return _P_+1;
}
#include calcTC.hCompile this file into a DLL with the name specified in the loadLibrary() Java call, and you're ready to go. Got all that? If not, take a look at the steps involved again, as well as at what the generated code is doing. This process will become easier after you have successfully completed it at least once.
#include stubsPreamble.h
//cut and paste the stub file
/* Stubs for class calcTC */
/* DO NOT EDIT THIS FILE - it is machine generated*/
/* SYMBOL: "calcTC\twos(I)I", calcTC_twos_stub,*/
_declspec(dllexport) stack_item
*calcTC_twos_stub(stack_item *_P_,struct execenv *_EE_)
{
extern int clacTC_twos(void *,int);
P_[0].i = calcTC_twos(_P_[0].p,((_P_[1].i)));
return _P_+1;
}
//implement the native method prot-typed in calcTC.h
int clacTC_twos(struct HcalcTC *this,int number)
{
return ~number;
}
No comments:
Post a Comment