Integration von Java in C++
Anwendungen
Matthias Müller – 19.11.2015 DOAG Jahreskonferenz 2015 Nürnberg
Die Datenbank-Spezialisten.
Zahlen und Fakten
Robotron Datenbank-Software GmbH
Gründungsjahr
1990
Geschäftsform
GmbH (9 Gesellschafter)
Mitarbeiterzahl
365 (Stand 10/2015)
Stammkapital
2,4 Mio. EUR
Umsatz 2014
31,2 Mio. EUR
Umsatz 2015
32,8 Mio. EUR
Hauptsitz
Oracle-Partner
ISO 9001 zertifiziert
Die Datenbank-Spezialisten.
Schulungs- und Kongresszentrum
Das Leistungsangebot von Robotron
methodische und technologische Kompetenzen
umfangreiches Fachwissen in den branchentypischen Prozessen
Die Datenbank-Spezialisten.
Agenda
Warum Java in C++?
Java Native Interface – Konzepte und Grundlagen
Integration von Java in C++ an einer Beispielanwendung
Probleme und Risiken
Best Practices
Fazit
Die Datenbank-Spezialisten.
Warum?
Die Datenbank-Spezialisten.
Warum Java in C++-Anwendungen?
Erweiterung bestehender Anwendungen um neue Funktionalitäten
„weiche“ Migration von C++-Anwendungen nach Java
Integration mit neueren Java-Anwendungen
Kostenersparnisse
Umgehung von Entwicklungsengpässen
Die Datenbank-Spezialisten.
Konzepte und Grundlagen
Die Datenbank-Spezialisten.
Java Native Interface - Einordnung
Standardisierte und herstellerunabhängige Schnittstelle der JVM
Verbindet C/C++ und Java zwei Richtungen
Die Nutzung von JNI erfolgt über eine dynamische Bibliothek
Plattformunabhängig und Binärkompatibel
Überwindet die Mängel anderer Ansätze (Netscape, Microsoft)
Die Datenbank-Spezialisten.
Java Native Interface – Zentrale Konzepte
Invocation und Interface API
Interface Pointer
Datentypen und Objekt-Referenzen
Objekt-Zugriff
Fehlerbehandlung
Die Datenbank-Spezialisten.
Java Native Interface – Das API
Java Invocation API
– Einbindung und Verwaltung einer JVM in nativen Code
Java Native Interface API
– Verwaltung und Zugriff auf Objekte der JVM
Die Datenbank-Spezialisten.
Java Native Interface – Interface Pointer
Die Datenbank-Spezialisten.
Java Native Interface – Datentypen
Einfache Datentypen
– Direkte Abbildung auf ihre korrespondierenden C/C++ Datentypen
– call by value-Semantik
Komplexe Datentypen und Klassen
– Verwendung von Referenzen
Die Datenbank-Spezialisten.
Java Native Interface – Referenzen
Globale Referenzen
– Threadübergreifend gültig
Schwache globale Referenzen (weak global references)
– Werden vom GC verwaltet
Lokale Referenzen
– Nur im erzeugenden Thread gültig
– Konvertierung in globale Referenzen
Die Datenbank-Spezialisten.
Java Native Interface – Objektzugriff
Erfolgt indirekt über eine Menge an Zugriffsfunktionen
– Ermittlung des Java-Class Objekts der Klasse
– Beschaffung der Methoden-Id
– Aufruf der Methode
Ausnahme sind Arrays
Die Datenbank-Spezialisten.
Java Native Interface – Fehlerbehandlung
JNI führt in vielen Fällen keine Fehlerprüfungen aus
Ausnahmen führen nicht direkt zu einer Unterbrechung
Eine Prüfung auf Ausnahmen erfolgt über
– Den Rückgabewert einer JNI-Funktion
– Dedizierte JNI-Funktionen (ExceptionOccured() oder ExceptionCheck())
Ausnahmen müssen explizit entfernt werden (ExceptionClear())
Bei pending exceptions ist die Ausführung der meisten JNI-Funktionen nicht sicher
Die Datenbank-Spezialisten.
Integration in C++
Die Datenbank-Spezialisten.
Integration in C++ am Beispiel
Generierung eines PDF-Formulars mittels XSL-FO
– Überführung eines XML-Formulars in eine PDF-Datei
– Java-Klassen implementieren den Transformationsprozess
– Ausführung der Transformation durch Apache FOP
– Signatur: int XML2PDF::transform(String xmlFile) throw Exception()
Voraussetzungen
– Java SE Development Kit
– C++-Compiler
Java 8 HotSpot VM
Die Datenbank-Spezialisten.
Beteiligte Komponenten
jvm.dll
C++
Quellen
CC
.exe
jni.h
jvm.lib
Die Datenbank-Spezialisten.
Java
Binaries
Einbindung der Java-VM
// JNI-Repräsentation der JVM
jni::JavaVM * pJavaVM;
// JNI-Struktur für Java-Zugriff in VM für den "Main Thread"
jni::JNIEnv * pJNIEnv;
// VM Optionen festlegen
jni::JavaVMInitArgs vm_args;
jni::JavaVMOption options[nMaxVMOptions];
options[0].optionString = const_cast<char *>(CLASS_PATH);
vm_args.nOptions = 1;
...
vm_args.options = options;
// VM Laden
jni::jint res = jni::JNI_CreateJavaVM(&pJavaVM, (void**)&pJNIEnv,
&vm_args);
Die Datenbank-Spezialisten.
Erzeugung des Formular-Generators
// Klassen-Objekt laden
jni::jclass clsXPdf = pJNIEnv->FindClass("jni/demo/XML2PDF");
if (clsXPdf == 0)
throw std::exception("JNI Fehler");
// Konstruktor beschaffen ...
jni::jmethodID jmiXPdf = pJNIEnv->GetMethodID(clsXPdf, "<init>",
"()V");
if (jmiXPdf == 0)
throw std::exception("JNI Fehler");
// ... und Instanz von XML2PDF erzeugen
jni::jobject jXPdf = pJNIEnv->NewObject(clsXPdf, jmiXPdf);
if (jXPdf == 0)
throw std::exception("JNI Fehler");
Die Datenbank-Spezialisten.
Aufruf der Transformationsmethode
// JNI Methoden-ID für Transformationsmethode beschaffen
jni::jmethodID jmiTransform =
pJNIEnv->GetMethodID(clsXPdf, "transform", "(Ljava/lang/String;)V");
if (jmiTransform == 0)
throw std::exception("JNI Fehler");
// Parameter-String erzeugen
jni::jstring jstrParam = pJNIEnv->NewStringUTF(XML_FILE);
if (jstrParam == 0)
throw std::exception("JNI Fehler");
// Transformation starten
pJNIEnv->CallVoidMethod(jXPdf, jmiTransform, jstrParam);
// Test auf pending Exceptions
if (pJNIEnv->ExceptionCheck() == JNI_TRUE)
throw std::exception("JNI Fehler");
Die Datenbank-Spezialisten.
Fehlerbehandlung
catch (const std::exception & e) {
jni::jthrowable jexc = pJNIEnv->ExceptionOccurred();
if (jexc) {
// Stacktrace auf stderr
pJNIEnv->ExceptionDescribe();
// Alle pending Exceptions aufräumen
pJNIEnv->ExceptionClear();
std::cerr << e.what() << ": " << What(pJNIEnv, jexc) <<
std::endl;
// Lokale Referenz zu Exception freigeben
pJNIEnv->DeleteLocalRef(jexc);
}
}
Die Datenbank-Spezialisten.
Ressourcenfreigabe
// JNI Objektreferenzen freigeben
if (clsXPdf != NULL)
pJNIEnv->DeleteLocalRef(clsXPdf);
if (jXPdf != NULL)
pJNIEnv->DeleteLocalRef(jXPdf);
if (jstrParam != NULL)
pJNIEnv->DeleteLocalRef(jstrParam);
Die Datenbank-Spezialisten.
Probleme und Risiken
Die Datenbank-Spezialisten.
Speicherbedarf der JVM
Zuteilung ausreichenden Speichers bei Start der VM
Keine dynamische Reallokation möglich
Die Java VM kann in einem Prozess nicht neu gestartet werden
Konsequenz ist ein Neustart der Anwendung, um die Speicherzuteilung zu ändern
Die Datenbank-Spezialisten.
Fehlerbehandlung
JNI prüft nicht auf Korrektheit der Argumente
Unbehandelte (pending) Ausnahmen führen zu subtilen Fehlern im Programmablauf
Fehler können zum Absturz der VM führen und damit einen Neustart der Anwendung
notwendig machen
Fehleranalyse ist teilweise aufwendiger
Die Datenbank-Spezialisten.
Internationalisierung
Native C/C++ Anwendungen sind oft an den Zeichensatz des Hosts gebunden
Java verwendet intern mit UTF-16 Unicode für die Zeichenkodierung
JNI bietet String-Zugriffsfunktionen für UTF-16 und modifiziertem UTF-8
– UTF-16 Strings sind nicht NULL-Terminiert
– Natives UTF-8 kann nicht as is an Java übergeben werden
Für andere Kodierungen/Zeichensätze müssen eigene Funktionen bereitgestellt werden
Die Datenbank-Spezialisten.
Eingeschränkte Compileranalyse
Verletzung der Sichtbarkeitsdefinitionen einer Klasse
– Der Aufruf einer Methode mit eingeschränkter Sichtbarkeit führt zu einem Laufzeitfehler
(IllegalAccessException)
Statische Typsicherheit kann nicht gewährleistet werden
– Verletzungen führen zu Laufzeitfehlern
JNI verwendet variable Parameterlisten in Methodenaufrufen
– Inkorrekte Behandlung der Argumentlisten führt teilweise zu schwer analysierbaren LaufzeitProblemen
Die Datenbank-Spezialisten.
Weitere Stolperfallen
Verletzung der Thread-Korrektheit
– JNI Environment zum Aufruf von JNI-Funktionen wird im falschen Thread verwendet
Fehlerhafte Ressourcenfreigabe
– Referenzen werden nicht wieder freigegeben
– Benutzung ungültiger Referenzen
Performance-Probleme bei komplexen Datentypen (Arrays) in der Schnittstelle
Die Datenbank-Spezialisten.
Best Practices
Die Datenbank-Spezialisten.
Korrektheit und Robustheit I
Fehlerprüfungen sind langweilig – aber WICHTIG
Kapselung der JNI-Strukturen und Funktionen
– Verwendung von Wrapper-Klassen
– Minimale Schnittstelle zu JNI-Funktionen
– Zentralisierung der Fehlerbehandlung
– Ressourcenfreigabe durch Dekonstruktor
Die Datenbank-Spezialisten.
Korrektheit und Robustheit II
Erstellung von Peer-Klassen für Java-Objekte
– Transparente Integration in C++-Code
– Codereduzierung
– Wartbarkeit
Mapping der Java-Ausnahmen in C++-Ausnahmen
Vernünftige Limitierung des Heap Space der Java VM
Die Datenbank-Spezialisten.
Performance
Caching von häufig benutzten JNI-Strukturen
– Attribut- und Methoden-Id
– Objekt-Referenzen
– JNI Environment JNIEnv des Threads
Sorgfältiges Design der Schnittstelle C++/Java
– Vermeidung iterativer Zugriffe auf Java-Arrays
– Häufige Kontextwechsel zwischen C++ und Java vermeiden
Rückgabewerte testen anstatt auf Ausnahmen
Die Datenbank-Spezialisten.
Fehleranalyse
Verwendung der Java-Option –Xcheck:jni
Schreiben von Log-Dateien in Java-Komponenten
Generierung von Debug-Information durch javac
Die Option –verbose:jni protokolliert die JNI-Aufrufe
Die Datenbank-Spezialisten.
Fazit
Die Datenbank-Spezialisten.
Fazit
Zuverlässige, plattformunabhängige und portable Schnittstelle
Mit einem kleinen Satz an Basisklassen gestaltet sich auch die Programmierung einfach
JNI-basierte Lösungen im Projekt auf über 3000 PC bisher ohne Probleme
Java Versionswechsel der Clients ohne neues Rollout der Anwendung
Die Datenbank-Spezialisten.
Matthias Müller
Senior Systemberater
Robotron Datenbank-Software GmbH
Stuttgarter Str. 29 | D-01189 Dresden
Tel. +49 (0) 351-25859 - 0
[email protected]
www.robotron.de
Fragen?
Die Datenbank-Spezialisten.