JNI – Java Native Interface – is an interface for cooperating Java and legacy code. Oracle RDBMS doesn’t support it officially in embedded Oracle JVM (aka “Aurora”):
Oracle Database does not support the use of JNI in Java applications. If you use JNI, then your application is not 100 percent pure Java and the native methods require porting between platforms. Native methods can cause server failure, violate security, and corrupt data.
All true – and nevertheless it’s working.
Here is an example for standalone Java. I’ve made the same for Oracle JVM.
- Compiling Java class, generating header file:
public class testJNI {
static {
System.loadLibrary("testjni");
}
public static native String nativeCall();
public static void print() {
String str = nativeCall();
System.out.println(str);
}
}
[oracle@localhost ~]$ javac testJNI.java
[oracle@localhost ~]$ javah -jni testJNI
[oracle@localhost ~]$ cat testJNI.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class testJNI */
#ifndef _Included_testJNI
#define _Included_testJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: testJNI
* Method: nativeCall
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_testJNI_nativeCall
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
- Writing function implementation, building library:
[oracle@localhost ~]$ cat testjni.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <jni.h>
#include <testJNI.h>
JNIEXPORT jstring JNICALL Java_testJNI_nativeCall(JNIEnv *env, jclass clazz)
{
jstring ret = 0;
char* tmpstring = "Test program of JNI.\n";
ret = (*env)->NewStringUTF(env, tmpstring);
return ret;
}
[oracle@localhost ~]$ gcc -shared -fpic -o libtestjni.so -I /u01/jdk1.5.0_22/include -I /u01/jdk1.5.0_22/include/linux testjni.c
- Loading class file into database, setting LD_LIBRARY_PATH (for connections via listener you should specify it with ENVS in listener.ora)
[oracle@localhost ~]$ loadjava -user tim/t testJNI.class [oracle@localhost ~]$ export LD_LIBRARY_PATH=/home/oracle
- Writing PL/SQL procedure wrapper for testJNI.print and trying to invoke it:
[oracle@localhost ~]$ sqlplus tim/t SQL*Plus: Release 11.2.0.1.0 Production on Sun Dec 13 20:14:27 2009 Copyright (c) 1982, 2009, Oracle. All rights reserved. Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production With the Partitioning option SQL> create or replace procedure test_jni as 2 language java name 'testJNI.print()'; 3 / Procedure created. SQL> set serveroutput on SQL> exec dbms_java.set_output(10000); PL/SQL procedure successfully completed. SQL> exec test_jni Exception in thread "Root Thread" java.lang.ExceptionInInitializerError Caused by: java.security.AccessControlException: the Permission (java.lang.RuntimePermission loadLibrary.testjni) has not been granted to TIM. The PL/SQL to grant this is dbms_java.grant_permission( 'TIM', 'SYS:java.lang.RuntimePermission', 'loadLibrary.testjni', '' ) at java.security.AccessControlContext.checkPermission(AccessControlContext.java) at java.security.AccessController.checkPermission(AccessController.java) at java.lang.SecurityManager.checkPermission(SecurityManager.java) at oracle.aurora.rdbms.SecurityManagerImpl.checkPermission(SecurityManagerImpl.java ) at java.lang.SecurityManager.checkLink(SecurityManager.java:820) at java.lang.Runtime.loadLibrary0(Runtime.java:816) at java.lang.System.loadLibrary(System.java:1167) at testJNI.<clinit>(testJNI.java:3) BEGIN test_jni; END; * ERROR at line 1: ORA-29532: Java call terminated by uncaught Java exception: java.lang.ExceptionInInitializerError ORA-06512: at "TIM.TEST_JNI", line 1 ORA-06512: at line 1
Exception says current user don’t have permission to load library; when you try to execute the provided statement under SYS it’ll fail:
SQL> conn / as sysdba Connected. SQL> exec dbms_java.grant_permission( 'TIM','SYS:java.lang.RuntimePermission', 'loadLibrary.testjni', '' ) Exception in thread "Root Thread" java.lang.SecurityException: policy table update SYS:java.lang.RuntimePermission, loadLibrary.testjni at oracle.aurora.rdbms.security.PolicyTableManager.checkPermission(PolicyTableManager.java) at oracle.aurora.rdbms.security.PolicyTableManager.activate(PolicyTableManager.java) at oracle.aurora.rdbms.security.PolicyTableManager.grant(PolicyTableManager.java) BEGIN dbms_java.grant_permission( 'TIM','SYS:java.lang.RuntimePermission', 'loadLibrary.testjni', '' ); END; * ERROR at line 1: ORA-29532: Java call terminated by uncaught Java exception: java.lang.SecurityException: policy table update SYS:java.lang.RuntimePermission, loadLibrary.testjni ORA-06512: at "SYS.DBMS_JAVA", line 793 ORA-06512: at line 1
By default even SYS can not modify Java RuntimePermission of loading a library:
SQL> select seq, kind, grantee, name, enabled from dba_java_policy where name like '%java.lang.RuntimePermission%'; SEQ KIND GRANTEE NAME ENABLED ---------- -------- ------------------------------ ------------------------------------------------------------ -------- 11 GRANT JAVA_ADMIN 0:java.lang.RuntimePermission#* ENABLED 95 RESTRICT PUBLIC 0:java.lang.RuntimePermission#loadLibrary.* ENABLED
and you need to disable it explicitly:
SQL> exec dbms_java.disable_permission(95); PL/SQL procedure successfully completed. SQL> exec dbms_java.grant_permission( 'TIM', 'SYS:java.lang.RuntimePermission', 'loadLibrary.testjni', '' ) PL/SQL procedure successfully completed. SQL> exec dbms_java.enable_permission(95); PL/SQL procedure successfully completed.
- Finally - invoke PL/SQL wrapper (which calls static Java method, which calls native C procedure…)
SQL> conn tim/t Connected. SQL> exec test_jni Test program of JNI. PL/SQL procedure successfully completed.
And once again: all that stuff is not supported by Oracle.


9 Comments
SQL> exec test_jni
BEGIN test_jni; END;
*
ERROR at line 1:
ORA-29532: Java call terminated by uncaught Java exception:
java.lang.UnsatisfiedLinkError: no testjni in java.library.path
ORA-06512: at “SYSTEM.TEST_JNI”, line 1
ORA-06512: at line 1
I’m getting the above error when I execute test_jni. Any ideas?
Solved the above pbm, now getting this
ORA-29532: Java call terminated by uncaught Java exception:
java.lang.NoClassDefFoundError
ORA-06512: at “SYSTEM.TEST_JNI”, line 1
ORA-06512: at line 1
Hello Mary,
the error says JVM couldn’t find Java class you are calling via PL/SQL wrapper. Did you load it properly?
Thanks for the response. I followed exactly the same steps outlined in your article. Yes I load the Java class using loadjava command. When I give “select name, source from user_java_classes” I can see my java class loaded in sql-plus. When I try a simple HelloWorld.java program without any JNI calls it is working well. I don’t know where I am wrong.
I am trying this out almost a day now.I am getting theerror “java.lang.UnsatisfiedLinkError: no testjni in java.library.path” for the first time when I execute the pl/sql procedure (exec “test_jni” )then when I try the next time I am getting the “java.lang.NoClassDefFoundError” Error
Thanks again,
Mary
I think the problem occurs the System.loadLibrary(“testjni”) call occurs. The libtestjni.so library is currently in my $HOME and my .bash_profile looks like the following:
ORACLE_HOME=/opt/oracle/product/11.2.0/dbhome_1
ORACLE_SID=orcl
PATH=$HOME:/usr/java/jdk1.5.0_22/bin:$PATH:$ORACLE_HOME/bin
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME:/usr/java/jdk1.5.0_22/lib:$ORACLE_HOME/lib
LD_LIBRARYN32_PATH=$HOME
How do I change this to make the pl/sql procedure to locate the testjni library file.
thanks
Mary
I’m not getting any output from the following .class file
public class Hello
{
public static String world()
{
String path = System.getProperty(“java.library.path”);
return(path);
}
}
if it has System.getProperty().
Any ideas?
Mary,
if you need some help, you should be prepared and make some efforts to correctly present your question – otherwise answers will include speculations, and I usually don’t like it. Here is how you can get java.library.path:
SQL> create or replace function hello_fnc(p_prop varchar2) return varchar2 as 2 language java name 'java.lang.System.getProperty(java.lang.String) return java.lang.String'; 3 / SQL> select hello_fnc('java.library.path') from dual; HELLO_FNC('JAVA.LIBRARY.PATH') ------------------------------------------------------ :/u01/app/oracle/product/10.2/libHere is a link to a thread on SQL.ru forum where someone successfully tried to invoke SAP Java Connector with a JNI library sapjco3.dll from Oracle.
Hi.
I also successfully connect directly from oracle to SAP with the sap jco2.
I don´t need a RMI Server like descriped in Kuassi Mensahs book.
I will test ne next days and I will write a todo.