Die Beispiel-Applikation bestehe aus zwei Java-Klassen Hello und Work, die jeweils eine native Methode enthalten. Die eine gibt eine Begrüßungsmeldung aus, die zweite berechnet etwas. Das Beispiel ist künstlich konstruiert, normalerweise würde dies kein Anwender durch native Methoden erledigen lassen.
Die native Methoden beider Klassen sollen in einer gemeinsamen Bibliothek example1 abgelegt werden.
Implementieren des Java-Codes
In einer Datei Hello.java sei die folgende Java-Klasse definiert:
class Hello { public native void greetings(String text); static { System.loadLibrary("example1"); } public static void main(String[] args) { new Hello().greetings("Hello"); new Work().compute(); } }
In der Datei Work.java sei die zweite Java-Klasse definiert:
import java.io.*; class Work { public native double docompute(double arg); public void compute() { System.out.println("Resultat 1: " + docompute(1.0)); System.out.println("Resultat 2: " + docompute(7.0)); System.out.println("Resultat 3: " + docompute(3.11)); } }
Sollen die native Methoden in unterschiedlichen Libraries abgelegt sein, müssten beide Klassen bei der Initialisierung ihre jeweilige Library laden.
Compilieren des Java-Codes
Die beiden Java-Klassen können jetzt mit dem Kommando
javac Hello.java
compiliert werden. Die abhängige Klasse Work wird bei dieser Übersetzung mit erzeugt.
Erzeugen der Header-Dateien
Die für die Implementierung der native Methoden benötigten Header-Dateien können mit dem Tool javah aus den Klassendateien generiert werden:
javah -jni Hello javah -jni Work
Als Ergebnis stehen die Header-Dateien Hello.h und Work.h mit den Prototypen der native Funktionen zur Verfügung.
Implementieren des C-Codes
Die Implementierung der native Methoden erfolgt nun typischerweise in entsprechenden Source-Dateien. Für unser Beispiel seien dies die Dateien Hello.c und Work.c. Beide Dateien inkludieren den mit JENV bereitgestellten Header jni.h und jeweils den zugehörigen zuvor generierten Header Hello.h bzw. Work.h. Die Funktionsdefinition muss zum generierten Prototyp passen. Die weitere Codierung hängt von der gewünschten Implementierung ab.
Das Programm Hello.c sei nun folgendermaßen implementiert:
#include <jni.h> #include "Hello.h" #include <stdio.h> #include <stdlib.h> #include <ascii_ebcdic.h> JNIEXPORT void JNICALL Java_Hello_greetings(JNIEnv *env, jobject jthis, jstring text) { char *ebcdic_text; const char *utf_text; utf_text = (*env)->GetStringUTFChars(env,text,NULL); ebcdic_text = _a2e_dup(utf_text); (*env)->ReleaseStringUTFChars(env,text,utf_text); printf("Hier meldet sich das Programm %s\n",ebcdic_text); free(ebcdic_text); }
Die Datei Work.c enthalte folgenden Code:
#include <jni.h> #include "Work.h" JNIEXPORT jdouble JNICALL Java_Work_docompute(JNIEnv *env, jobject jthis, jdouble num) { return (num < 1.7) ? num * 3.4 : num - 1.0; }
In der Datei Work.c wurde von der weiter oben beschriebenen Möglichkeit der transparenten Nutzung der IEEE-Funktionen Gebrauch gemacht. In der Datei Hello.c werden explizite ASCII-EBCDIC-Konvertierungen durchgeführt.
Um die Beispiele übersichtlich und klein zu halten, wurde auf ausführliche Fehlerbehandlung verzichtet.
Übersetzen der C-Sources
Die im vorigen Abschnitt implementierten C-Sources müssen nun mit den richtigen Compiler-Optionen übersetzt werden. Für Hello.c sind das die Standard-Optionen, die weiter oben beschrieben wurden:
cc -c -I<Installations-Pfad>/include \ -Kllm_keep,llm_case_lower \ -Kworkspace_stack,c_names_unlimited Hello.c
Für Work.c muss zusätzlich noch die IEEE-Arithmetik berücksichtigt werden:
cc -c -I<Installations-Pfad>/include \ -Kllm_keep,llm_case_lower \ -Kworkspace_stack,c_names_unlimited \ -Kieee_floats Work.c
Als Ergebnis stehen die Objekt-Dateien zur Verfügung.
Erzeugen des Shared Objects
Mit dem folgenden Kommando können die zuvor erzeugten Objekte zu einem Großmodul gebunden werden:
cc -r -B llm4 -o example1.o Hello.o Work.o
Anschließend wird der erzeugte Großmodul in einer BS2000-Bibliothek abgelegt:
bs2cp example1.o bs2:'syslnk.example1(example1,L)'
Zuletzt wird eine Beschreibungsdatei entsprechend den Namenskonventionen erzeugt, die die richtigen Verweise enthalten muss:
mk_shobj -l syslnk.example1 -m example1 libexample1.so
Ablauf des Programms
Für den Ablauf des Programms ist es jetzt nur noch notwendig, die Umgebungsvariable LD_LIBRARY_PATH so einzustellen, dass das erzeugte Shared Object auch gefunden wird. In unserem Beispiel ist dies mit
export LD_LIBRARY_PATH=.
möglich. Die Anwendung kann nun mit
java Hello
zum Ablauf gebracht werden.