Java Native Interface Application Notes
Total Page:16
File Type:pdf, Size:1020Kb
Java Native Interface Application Notes Da Ke 4/5/2009 ECE 480 Spring 2009, Design Team 3 Department of Electrical and Computer Engineering Michigan State University Abstract Java is one of most widely used programming language today due to its openness, ability to scale up and portability. The language is design to have a simpler object model and fewer low-level facilities like pointer methods in C/C++. Sometime this could impose a limitation on what a program can do. This application note will explore various ways of implementation that will allow Java to interact with some programs that are written in lower level language. Keywords: Java, JVM, JNI, Linux, Windows, Operating System, Native interface, Native code Introduction Most modern high level programming languages today are capable of handling what once consider trivial tasks for developers like memory management. However, this doesn't come without cost. A Java application does not interact with underlying system infrastructure directly instead it first compile source code to bytecode and run on Java virtual machine which itself is an application that run on top of the operating system. The Java virtual machine acts like a mediator between the application and the operating system. Most modern implementations of Java Virtual Machine does include several interfaces and libraries that we can utilize to allow Java applications to perform some system level tasks and even speed up the execution of the program by handing over some more resource-intense operations to programs that are runs natively on the machine. Objective This application note will explain different approaches to implement system level functions using Java Programming Language. The goal is for the reader with basic understanding of Java to understand different ways of interacting with operating system in Java and what are the trade-offs. Background The ability to access system resource is essential for programs that are design to be flexible and expandable. In an embedded environment where system resource is both limited and considerably slower than conventional computing environment. It’s extremely important for an application to effectively manage and utilize system resource to both improve the performance and stability. The Java Programming Language is designed to create applications across many different platforms. By utilize different Java libraries to communicate Java application directly with the system and native programs, one will find the run time efficiency of Java application can be greatly optimized. Approaches Java Native Interface (JNI) Java Native Interface is a native programming interface for Java Programming Language. It allows Java code runs inside of a Java Virtual Machine (JVM) to interoperate with applications or libraries that is written in some other lower level programming languages such as C, C++ and assembly. With JNI developers are able to utilize existing libraries written in other languages and incorporate these existing functionalities into their Java application. JNI for C/C++ Program Most modern java compiler provides an interface library jni.h that allows C/C++ program to access and manipulate Java objects. This is all done by C/C++ memory pointers. As shown in Figure 1, the JNI is implemented using direct memory mapping. Therefore, the usage and allocation of memory is effectively managed by the JVM. JNI allows the programmer to pass different Java objects as parameters to C/C++ program and gets the return value from the native program converts it back to the java object. Figure 1: JNI Pointers and Functions Figure 2: Java Native Interface illustration in C/C++ Example Program in C I’ll go through a simple example of how to create a C function and interface with Java application using JNI. There are 5 steps to do this as you can see from Figure 2: 1. Write the Java Code This is a simple Java program with a native method declared – the Do_thing1 method. The program will call Do_thing1 method when it gets executed. 2. Compile the Java Code This step is very simple all you need to do is run your favorite Java compiler. Make sure it supports JNI. The command to do this under GNU/Linux is: javac Example1.java 3. Create the header (.h) File If your Java compiler is equipped with JNI support, you should be able to generate a general C/C++ header file that contains information that JNI needs to identify a C/C++ program. You need to make sure your Java source code was successfully compiled. To generate the JNI header file under GNU/Linux just run: javah –jni Example1 4. Implement the Native Method In this step you will need to either port your original native code into JNI compatible form or start implementing a new one. For our example, I’ll try to keep it simple. In the header file generated by javah in previous step you will find: This is a declaration of the native method with two parameters. The first parameter JNIEnv is a pointer that allows your native code to access parameters passed in from the Java application. The second parameter jobject is a reference to current instance of Java’s class. Now we need to provide an implementation of to this native method. This is a very simple function that just prints out string “This is Example1” using C standard I/O library. When the Java application gets execute, this module will be print out the string. 5. Create a Shared Library In step 1, we loaded the native library named example1, the file name that JVM expected for the shared library will be different depend of operating system. For example, under most Linux/Unix systems the JVM will expect library name libexample1.so for the above example while the Microsoft Windows will expect example1.dll To compile the native application under Linux: gcc -o libexample1.so -shared -Wl,-soname,libexample1.so –I /path/to/your/jdk/lib/include –I /path/to/your/jdk/lib/include/linux Example1.c - static –lc It’s important to set the correct environmental variable so that JVM knows where to find the shared library. To do this under Linux: LD_LIBRARY_PATH=`pwd` export LD_LIBRARY_PATH Where the `pwd` is command that printing out the current working directory. You need to change this accordingly. After the Environmental variable is set you should be able to run you Java application with native method. Alternative Approach: Java Runtime Object Java also provides another simple and easy interface to interact with operating system – the Runtime object. The Runtime object is a special object that associated with current Java application. It’s able to send commands as a string to system command shell. The command shell is different across different operating system therefore most of the commands will not be usable if operating system is changed. Nevertheless, it’s an easy and effective way to execute a native application. Figure 3: Java Runtime Command Execution Illustration As you can see from above figure, using Runtime object is much simpler compare to JNI. There are a lot fewer steps involve. However, the communication between the native process and Java application is somewhat limited - data transfer in between are restricted to String, I/O Exception and Interrupt. To launch an external process, first you need to create a Process object and attach it to the new Process created by Runtime object from the command string that user specify: In order to get output produce by the external process, you will need a BufferedReader object. You can choose to output the string captured from external process: You can also implement the Exception handler in this block of code. If there is an exception occurred while getting the output from the external process that’s usually an indication that the process had failed to launch. Conclusion A Java application with system-specific implementation usually scarifies the portability of the application in exchange for the efficiency of the program. However, there are different ways to go around that. For example, you can provide different implementations of native code for various platforms and let Java Virtual Machine decide which implementation to use. This way we will have a relative more efficient application, and still able take advantage of many great features provides by Java. References: JNI Design (Sun Microsystem): http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/design.html Java Runtime Object Reference (Sun Microsystem): http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Runtime.html JNI in Wikipedia: http://en.wikipedia.org/wiki/Java_Native_Interface .