jni on linux

1. create Message.java, define native function and load library

[dennis@localhost jni]$ cat Message.java
class Message
{ 
    public native int writeMessage(int type, char page_num, String content); 
    public native int getCPUTemperature(); 
    public native int getHDDTemperature(); 

    static 
    { 
        System.loadLibrary("Message"); 
    }  
}

2. run ‘javac Message.java’ to generate Message.class

[dennis@localhost jni]$ javac Message.java 

3. run ‘javah Message’ to generate Message.h

[dennis@localhost jni]$ javah Message
[dennis@localhost jni]$ cat Message.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Message */

#ifndef _Included_Message
#define _Included_Message
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Message
 * Method:    writeMessage
 * Signature: (ICLjava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_Message_writeMessage
  (JNIEnv *, jobject, jint, jchar, jstring);

/*
 * Class:     Message
 * Method:    getCPUTemperature
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_Message_getCPUTemperature
  (JNIEnv *, jobject);

/*
 * Class:     Message
 * Method:    getHDDTemperature
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_Message_getHDDTemperature
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

4. create Message.c, and implement function

[dennis@localhost jni]$ cat Message.c
#include <jni.h>
#include <stdio.h>
#include "Message.h"

int iCpu;
int iHdd;
int iMainboard;
int iFan;

void ReadTemperatureIni()
{
    iCpu = 37;
    iHdd = 28;
    iMainboard = 30;
    iFan = 3200;
    printf("call %s %s %d\n", __FILE__, __func__, __LINE__);
}

void send_msg(const short code, const char page, const char *content) 
{
    printf("code=%d, page=%d, content=%s\n", code, page, content);
    printf("call %s %s %d\n", __FILE__, __func__, __LINE__);
}

JNIEXPORT jint JNICALL Java_Message_getCPUTemperature(JNIEnv *env, jobject obj)
{
    ReadTemperatureIni();
    return iCpu;
}

JNIEXPORT jint JNICALL Java_Message_getHDDTemperature(JNIEnv *env, jobject obj)
{
    ReadTemperatureIni();
    return iHdd;
}

JNIEXPORT jint JNICALL Java_Message_getMainboardTemperature (JNIEnv *env, jobject obj)
{
    ReadTemperatureIni();
    return iMainboard;    
}

JNIEXPORT jint JNICALL Java_Message_getCPUFanSpeed (JNIEnv *env, jobject obj)
{
    ReadTemperatureIni();
    return iFan;
}


JNIEXPORT jint JNICALL Java_Message_writeMessage 
(JNIEnv *env, jobject obj, jint type, jchar page_num, jstring content)
{
    /* c   code use: (*env)-> */
    /* c++ code use: env->    */
    const jbyte *str = (const jbyte *)(*env)->GetStringUTFChars(env,content,JNI_FALSE);
    send_msg(type, page_num, (const char*)str);
    (*env)->ReleaseStringUTFChars(env,content,(const char *)str);

    return 0;
}

5. start to compile file to dynamic library, then copy the *.so file to /usr/lib64/

[dennis@localhost jni]$ cat Makefile 
CC = gcc 
CFLAGS = -Wall -shared -fPIC
# change the directory for YOUR OS
JAVA_INC = -I/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.60-2.5.0.1.fc20.x86_64/include/  \
           -I/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.60-2.5.0.1.fc20.x86_64/include/linux 
TARGET = libMessage.so

all:$(TARGET)

libMessage.so: Message.c
    $(CC) $(CFLAGS) $(JAVA_INC) -o $@ $^

.PHONY:clean
clean:
    rm -f *.class $(TARGET)
[dennis@localhost jni]$ make
gcc  -Wall -shared -fPIC -I/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.60-2.5.0.1.fc20.x86_64/include/ -I/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.60-2.5.0.1.fc20.x86_64/include/linux  -o libMessage.so Message.c
[dennis@localhost jni]$ su -c 'cp libMessage.so /usr/lib64'

6. create Test.java, a sample code to test interface function

[dennis@localhost jni]$ cat Test.java 
public class Test
{
     public static void main(String argv[])
     {
         new Test();
     }

     public Test()
     {
         char type = 0x1F;
         char page = 1;
         String content = "Test Message";
         int ret = new Message().writeMessage(type, page, content); 

         int cpu=new Message().getCPUTemperature();
         System.out.println(cpu);     

         int hdd=new Message().getHDDTemperature();
         System.out.println(hdd);
     }
}

7. run ‘javac Test.java’

[dennis@localhost jni]$ javac Test.java    

8. run ‘java Test’

[dennis@localhost jni]$ java Test 
code=31, page=1, content=Test Message
call Message.c send_msg 22
call Message.c ReadTemperatureIni 16
37
call Message.c ReadTemperatureIni 16
28

A full version Makefile, support compile java code

#################################################################
# Makefile 
# For JNI project on Fedora x86_64 release 20
# Create by Dennis
# 2014-07-18
#
# HOW TO MAKE A JNI PROJECT
# 1. create Message.java, define native function and load library
# 2. run 'javac Message.java' to generate Message.class
# 3. run 'javah Message' to generate Message.h
# 4. create Message.c, and implement function
# 5. start to compile file to dynamic library, then copy the *.so 
#    file to /usr/lib64/
# 6. create Test.java, a sample code to test interface function
# 7. run 'javac Test.java' to generate Test.class
# 7. run 'java Test' 
#################################################################
CC = gcc 
JAVAC = javac
CFLAGS = -Wall -shared -fPIC
# change the directory for YOUR OS
JAVA_INC = -I/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.60-2.5.0.1.fc20.x86_64/include/  \
           -I/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.60-2.5.0.1.fc20.x86_64/include/linux 
TARGET = libMessage.so Test.class

all:$(TARGET)

libMessage.so: Message.c
    $(CC) $(CFLAGS) $(JAVA_INC) -o $@ $^

Test.class: 
    $(JAVAC) Test.java    

.PHONY:clean
clean:
    rm -f *.class $(TARGET)

Reference