Java Native Calls

Werbung
Java Native Calls
Einbinden von C Bibliotheken in Java Klassen
Prof. Dr. Nikolaus Wulff
GUI und Model
• Die DeviceEditor GUI ist in Java implementiert.
• Die Anwendung ist allerdings ohne eine fachliche
Logik ein reines „Malwerkzeug“.
• Die fachliche Logik des elektrischen Bauteile
Beispiels besitzt eine C Implementierung.
• Was fehlt ist eine Erweiterung der graphischen
Klassen um die fachliche Logik:
• Entweder die C Implementierung in Java neu zu
implementieren oder aber
• die graphischen Bauteile als Adapter zu verwenden,
die an die fachliche C Implementierung delegiert.
© Prof. Dr. Nikolaus Wulff
Informatik III
2
MVC beim DeviceEditor
View
JComponent
(from
Painter
<<Interface>>
Paintable
manages
(from
0..*
(from painter)
DevicePainter
(from v iew )
DeviceController
(from controller)
delegates
DeviceGUI
/ manage
Device
peer
(from vie w)
(from
0..*
1
<<Interface>>
MouseListener
(from j av a.aw t)
ResistorGUI
(from v iew )
Resistor
/delegates
(from model)
1
CapacitorGUI
(from vi ew )
CrossWire
(from
Controller
© Prof. Dr. Nikolaus Wulff
MouseAdapter
Capacitor
/delegates
(from model)
1
(from j av a.aw t)
View Adapter
Informatik III
Model
3
Einbinden von C in Java
• Die Scheinwiderstände der Devices wurden am
Anfang des Semesters mit Hilfe von C Methoden
realisiert.
• Wie lässt sich diese Implementierung wieder
verwenden?
• Neu- bzw. Nachimplementierung in Java
• C Routinen in Java Code einbinden
• Welcher Ansatz verwendet wird richtet sich nach
dem Aufwand und Nutzen...
© Prof. Dr. Nikolaus Wulff
Informatik III
4
Shapes kanonische Form
• Die Aufteilung in Methoden und Attribute erfolgt
in zwei Structs XXX_Instance und XXX_Class:
typedef struct Shape_Instance_struct* Shape;
typedef struct Shape_Class_struct {
void (*draw)
(Shape aShape);
void (*erase) (Shape aShape);
void (*moveTo) (Shape aShape, int x ,int y);
} ShapeClass;
typedef struct Shape_Instance_struct {
ShapeClass *class;
int pos_X;
int pos_Y;
<<Data>>
} ShapInstance;
ShapeInstance
ShapeClass
pos_X
pos_Y
© Prof. Dr. Nikolaus Wulff
Informatik III
<<Methods>>
ShapeClass
1
moveTo()
moveBy()
5
Widerstand ADT
/**
* Resistor.h
* Definition of Resistor ADT
* $Id: Resistor.h,v 1.1 2004/10/26 10:07:27 nwulff Exp $
*/
#ifndef __RESISTOR_H_
#define __RESISTOR_H_
#include "Device.h"
typedef struct resistor_struct* Resistor;
struct resistor_struct {
Impedance
impedance;
Conductance conductance;
double resistance;
char
type;
char* name;
};
extern Device createResistor(double resistance);
#endif /* __RESISTOR_H_ defined */
© Prof. Dr. Nikolaus Wulff
Informatik III
6
Native Code
• Java bietet die Möglichkeit Klassen mit Methoden
zu schreiben, die in C realisiert werden.
• Hierzu werden die Methoden mit dem Schlüsselwort native markiert, ohne das eine Implementierung in Java erfolgt.
public class Resistor extends Device {
/* (non-Javadoc)
* @see model.Device#getConductance(double)
*/
@Override
public native Complex getConductance(double omega);
}
© Prof. Dr. Nikolaus Wulff
Informatik III
7
C Header-Dateien generieren
• Nach dem Übersetzen von Resistor.java wird mit
dem Tool javah ein C Header-Datei Resistor.h
generiert.
• In dieser stehen die Deklarationen der fehlenden zu
implementierenden nativen C/Java Funktionen.
• Eine entsprechende Implementierung Resistor.c
wird dann zu einer Bibliothek gebunden.
Resistor.h
Resistor.j ava
Resistor.c
libResistor.so
© Prof. Dr. Nikolaus Wulff
Informatik III
8
Resistor.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class model_Resistor */
#ifndef _Included_model_Resistor
#define _Included_model_Resistor
#ifdef __cplusplus
extern "C" {
Complex getConductance(double omega);
#endif
/*
* Class:
model_Resistor
* Method:
getConductance
* Signature: (D)Lmath/Complex;
*/
JNIEXPORT jobject JNICALL
Java_model_Resistor_getConductance
(JNIEnv *, jobject, jdouble);
#ifdef __cplusplus
}
#endif
#endif
© Prof. Dr. Nikolaus Wulff
JVM
Informatik III
Resistor
9
Resistor.c howto?
• Wie kann jetzt die C Methode implementiert
werden?
• Benötigt wird nicht nur der Wert omega, sondern
auch der Widerstand (bzw. die Kapazität etc) des
jeweiligen Bauteils.
• Ausserdem muss ein neues Java Objekt vom Typ
Complex zurückgegeben werden. Dies kann kein
einfacher C-struct sein...
• Es lassen sich nicht nur von Java aus C Routinen
rufen, sondern diese können auch ihrerseits wieder
auf Java Klassen, Objekten und Methoden
zurückgreifen!
© Prof. Dr. Nikolaus Wulff
Informatik III
10
Java Reflection
• Jedem Java Objekt ist eineindeutig ein Class Objekt
zugeordnet.
– Class c = obj.getClass()
• Dieses Class Objekt enthält Metainformationen und
bietet „Java FunctionPointer“:
– Method m = c.getDeclaredMethod(name, ...)
– Field f = c.getDeclaredField(name)
• Diese „FunctionPointer“ erlauben das Objekt zu
manipulieren:
– double x = f.getDouble(obj)
– m.invoke(obj, ...)
© Prof. Dr. Nikolaus Wulff
Informatik III
11
Java Reflection API
Cl ass
Object
Package
1
name :
MyClass
myAt tribut e
<<Interface>>
Member
myM ethod()
Constructor
(from
© Prof. Dr. Nikolaus Wulff
Field
(from
Informatik III
Method
(from
12
Native Code API
• Alle C Methoden erhalten eine Referenz auf die
JVM Umgebung und das entsprechende Java
Objekt, dessen native Methode entwickelt wird.
• Dieses „Umgebungsobjekt“ ist eine C Struktur, die
verschieden FunctionPointer anbietet, um Methoden und Felder beliebiger Objekt zu addressieren.
• Ermitteln des Class Objekts von obj
jclass clazz = (*env)->GetObjectClass(env, obj);
• Ermitteln der Methode „double getValue()“ :
Signatur
jmethodID method =
(*env)->GetMethodID(env, clazz, "getValue", "()D");
© Prof. Dr. Nikolaus Wulff
Informatik III
13
Zugriff auf Felder
• Felder können direkt aus C addressiert werden.
• Es wird keine Rücksicht auf private genommen!
jfieldID field;
field = (*env)->GetFieldID(env, clazz, "x", "D");
(*env)->SetDoubleField(env, complex, field, 1.0);
• Die zu verwendenen C Methoden sind in der Datei
<jni.h> deklariert.
© Prof. Dr. Nikolaus Wulff
Informatik III
14
Aufruf von Funktionen
• Aufruf der Methode „getValue“:
double x;
x = (*env)->CallDoubleMethod(env, obj, method);
• Gegenstück „setValue“:
Signatur
method = (*env)->GetMethodID(env, clazz, "setValue", "(D)V");
(*env)->CallVoidMethod(env, obj, method, x);
• Die Signatur dient dazu überladene Methoden
eindeutig zu identifizieren.
• Wie kann effizient die genaue Signatur der
Methode ermittelt werden?
© Prof. Dr. Nikolaus Wulff
Informatik III
15
Java Disassembler
• Der Java Disassembler javap gestattet es in das
Innere von Java Klassen zu schauen.
• Mit den Parametern -p -s liefert javap die Signatur
Informationen:
~/workspace/JDevices/bin> javap -s -p model.Resistor
Compiled from "Resistor.java"
public class model.Resistor extends model.Device{
public model.Resistor();
Signature: ()V
private native void calculateImpedance(math.Complex, double);
Signature: (Lmath/Complex;D)V
public math.Complex getImpedance(double);
Signature: (D)Lmath/Complex;
public native math.Complex getConductance(double);
Signature: (D)Lmath/Complex;
}
© Prof. Dr. Nikolaus Wulff
Informatik III
16
Objekterzeugung
• Primitive Datentypen können dirket zurückgegeben
werden. Objekte müssen erst erzeugt werden:
jclass clazz;
jmethodID ctor;
jobject complex;
clazz = (*env)->FindClass(env, "math/Complex");
assert(clazz != NULL);
Konstruktor
Signatur
ctor = (*env)->GetMethodID(env, clazz, "<init>", "()V");
assert(ctor != NULL);
complex = (*env)->NewObject(env, clazz, ctor);
assert(complex != NULL);
return complex;
© Prof. Dr. Nikolaus Wulff
Informatik III
17
Einbinden der C Bibliothek
• Vor dem Verwenden von native Klassen muß die
zugehörige C Bibliothek geladen werden.
• Diese hat immer den generischen Namen
– libXXX.so für Unixe
– libXXX.dll für Windows
• Geladen wird sie am Besten beim Start der
Anwendung mit dem Aufruf:
– System.loadLibrary("XXX");
• gesucht wird dann im java.library.path. Oder mit
expliziter Pfadangabe (Achtung nicht portabel!):
– System.load("/pfad/libXXX.so");
© Prof. Dr. Nikolaus Wulff
Informatik III
18
Warnungen
• Mit dem C Code ist es möglich auf jedes Feld und
jede Methode der JVM zuzugreifen.
• Sogar eigene Semaphore, Mutexe und critical
Sections können geschrieben werden.
• Es ist möglich die gesamte JVM lahmzulegen.
• Es ist daher Vorsicht angebracht.
• Am Besten keine eigenen
Synchronisationsmechanismen in C!
• Kein malloc und free etc.
• Keine globalen Referenzen auf Objekte!
• Objekte mit Java Mitteln erzeugen, damit der
Garbage Collector den Speicher verwaltet.
© Prof. Dr. Nikolaus Wulff
Informatik III
19
Java und C ein gutes Gespann
• Mit Hilfe der Java Native API bleiben keine
Wünsche mehr offen.
• Ein guter Programmierer kann bis auf Betriebssystemebene gehen, sogar Assembler ist möglich.
• Die Eclipse ist ein gutes Beispiel für Java und C.
• Eclipse verwendet weder AWT noch Swing für die
GUI sondern das selbstentwickelte SWT.
• SWT ist eine Bibliothek, die aus graphischen
Klassen besteht, die vollkommen in C
implementiert sind und direkt delegieren an die
Widgets des jeweiligen Betriebsystems.
© Prof. Dr. Nikolaus Wulff
Informatik III
20
Herunterladen