Saturday 10 December 2016

Java programming with JNI:

THE Java  Native Interface (JNI) is a powerful feature of the Java platform.
Applications that use the JNI can incorporate native code written in programming languages such as C and C++, as well as code written in the Java programming
language.

The JNI is a powerful feature that allows you to take advantage of the Java
platform, but still utilize code written in other languages. As a part of the Java virtual machine implementation, the JNI is a two-way interface that allows Java
applications to invoke native code and vice versa.

You can use the JNI to write native methods that allow Java applications to
call functions implemented in native libraries.
When to Use the JNI
• A Java application may communicate with a native application through a
TCP/IP connection or through other inter-process communication (IPC)
mechanisms.
• A Java application may connect to a legacy database through the JDBC™
API.
• The Java API might not support certain host-dependent features needed by an
application. An application may want to perform, for example, special file
operations that are not supported by the Java API,
• You may want to implement a small portion of time-critical code in a lowerlevel language, such as assembly. If a 3D-intensive application spends most of its time in graphics rendering, you may find it necessary to write the core portion
of a graphics library in assembly code to achieve maximum performance.

Explain the advantages and disadvantages of using JNI.

Advantages of JNI : 
-Using JNI, we can access C and C++ code which adds performance boost to JAVA. 
- JNI allows JAVA to access some hardware features using other languages like C and C++.
- Use the existing library that was previously written in another languages. 
- Use of Windows API functions.
- Increasing the speed of execution.
- Invoke API functions from server product that is developed in C or C++ from a Java client.

Disadvantages of JNI : 

- JNI uses native languages which mean it has portability issue.
- Code debug is big problem for the developers who use JNI features in JAVA
- Write Once Run Anywhere is not possible.
- Run time errors debugging is difficult in native code.
- An applet can not call a native method.  - Security risk is potential.
Performance
Native code used to be up to 20 times faster than Java, when running in interpreted mode  .Allow Java to tap into low level O/S, H/W routines

Tools and components
To run the examples in this tutorial, you will need the following tools and components:
>A Java virtual machine (JVM)
>A Java compiler: java
>A native method C file generator: javah
Library files and native header files that define JNI. The jni.h C header file, jvm.lib, and jvm.dll or jvm.so files all ship with the SDK.
>A C and C++ compiler that can create a shared library. The two most common C compilers are Visual C++ for Windows and cc for UNIX-based systems.

->Six steps to call C/C++ from Java code

The process of calling C or C ++ from Java programs consists of six steps. We'll go over each step in depth in the sections that follow, but let's start with a quick look at each one.
1) Write the Java code. We'll start by writing Java classes to perform three tasks: declare the native method we'll be calling; load the shared library containing the native code; and call the native method.
2) Compile the Java code.
We must successfully compile the Java class or classes to bytecode before we can use them.
3) Create the C/C++ header file. The C/C++ header file will declare the native function signature that we want to call.
This header will then be used with the C/C++ function implementation (see Step 4) to create the shared library (see Step 5).
4) Write the C/C++ code. This step consists of implementing the function in a C or C++ source code file. The C/C++ source file must include the header file we created in Step 3.
5) Create the shared library file. We'll create a shared library file from the C source code file we created in Step 4.
6) Run the Java program. We'll run the code and see if it works. We'll also go over some tips for dealing with the more commonly occurring errors.

Declare the Native Method

You begin by writing the following program in the Java programming language.
The program defines a class named HelloWorld that contains a native method, print.

class HelloWorld
{
    private native void print();
    public static void main(String[] args)
    {
         new HelloWorld().print();
     }
     static 
      {
          System.loadLibrary("HelloWorld");
             // or System.load("give absolute path of library");
      }
 }

The HelloWorld.class definition begins with the declaration of the print native method. This is followed by a main method that instantiates the HelloWorld.class and invokes the print native method for this instance. The last part of the class definition is a static initializer that loads the native library containing the
implementation of the print native method.

There are two differences between the declaration of a native method such as print and the declaration of regular methods in the Java programming language.
A native method declaration must contain the native modifier. The native modifier indicates that this method is implemented in another language. Also, the native method declaration is terminated with a semicolon, the statement terminator symbol, because there is no implementation for native methods in the class itself. We will implement the print method in a separate C file.

Before the native method print can be called, the native library that implements print must be loaded. In this case, we load the native library in the static initializer of the HelloWorld.class. The Java virtual machine automatically runs the static initializer before invoking any methods in the HelloWorld.class, thus
ensuring that the native library is loaded before the print native method is called. We define a main method to be able to run the HelloWorld.class. HelloWorld.main calls the native method print in the same manner as it would call a regular method.

System.loadLibrary takes a library name, locates a native library that corresponds to that name, and loads the native library into the application. We will discuss the exact loading process later in the book. For now simply remember that in order for System.loadLibrary("HelloWorld") to succeed, we need to create a
native library called HelloWorld.dll on Win32, or libHelloWorld.so on linux.


Compile the HelloWorld Class

After you have defined the HelloWorld.class, save the source code in a file called HelloWorld.java. Then compile the source file using the javac compiler that comes with the JDK

javac HelloWorld.java

This command will generate a HelloWorld.class file in the current directory.


Create the Native Method Header File

Next we will use the javah tool to generate a JNI-style header file that is useful when implementing the native method in C. You can run javah on the HelloWorld.class as follows:

javah -jni HelloWorld

The name of the header file is the class name with a “.h” appended to the end
of it.
 The most important part of the header file is the function prototype for Java_HelloWorld_print, which is the C function that implements the HelloWorld.print method:

JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *, jobject);

Write the Native Method Implementation

The JNI-style header file generated by javah helps you to write C or C++ implementations for the native method. The function that you write must follow the prototype specified in the generated header file. You can implement the HelloWorld.print method in a C file HelloWorld.c as follows:

#include <jni.h>
#include <stdio.h>
#include "HelloWorld.h"
JNIEXPORT void JNICALL Java_HelloWorld_print(JNIEnv *env, jobject obj)
{
      printf("Hello World!\n");
      return;
}

The implementation of this native method is straightforward. It uses the printf function to display the string “Hello World!” and then returns.

The C program includes three header files:
• jni.h — This header file provides information the native code needs to call JNI functions. When writing native methods, you must always include this file in your C or C++ source files.
• stdio.h — The code snippet above also includes stdio.h because it uses the printf function.
• HelloWorld.h — The header file that you generated using javah. It includes the C/C++ prototype for the Java_HelloWorld_print function.

Compile the C Source and Create a Native Library
Remember that when you created the HelloWorld.class in the HelloWorld.java file, you included a line of code that loaded a native library into the program:
System.loadLibrary("HelloWorld");
Now that all the necessary C code is written, you need to compile HelloWorld.c and build this native library.
Different operating systems support different ways to build native libraries. On Linux, the following command builds a shared library called HelloWorld.so:

gcc -c -fPIC -I/usr/lib/jvm/java-8-openjdk-amd64/include -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux HelloWorld.c -o HelloWorld.o

gcc HelloWorld.o -shared -o HelloWorld.so

C compiler to generate a shared library instead of a regular Linux executable file.

Run the Program
At this point, you have the two components ready to run the program. The classfile (HelloWorld.class) calls a native method, and the native library (HelloWorld.so) implements the native method.

java -Djava.library.path=. HelloWorld

You should see the following output:
Hello World!

2 comments: