2013-07-21 6 views
7

Ich verwende Java Web Start, um eine Java-Anwendung zu starten, die von nativen Bibliotheken von Drittanbietern abhängig ist. Diese systemeigenen Bibliotheken laden anschließend eine andere native Bibliothek (commonLib) als ihre Abhängigkeit mit LoadLibrary/dlopen.Java Web Start - native Abhängigkeit mit einer anderen nativen Abhängigkeit laden

Wenn Web Start nicht verwendet wird, funktioniert alles wie erwartet, wenn sich die systemeigenen Bibliotheken im selben Verzeichnis befinden.

Web Start jedoch die nativen Bibliotheken erfordert in einer JAR-Datei und verwiesen in der jnlp-Datei gepackt werden, was ich getan habe:

<!-- Windows OS --> 
    <resources os="Windows"> 
     <nativelib href="native/native-windows.jar" /> 
    </resource> 

    <!-- Linux OS --> 
    <resources os="Linux"> 
     <nativelib href="native/native-linux.jar" /> 
    </resources> 

    <!-- Mac OSX --> 
    <resources os="Mac OS X"> 
     <nativelib href="native/native-osx.jar"/> 
    </resources> 

Die nativen Bibliotheken laden in Ordnung, aber sie versagen, ihre Abhängigkeit laden commonLib - Der C++ LoadLibrary/dlopen-Aufruf schlägt fehl, da die Datei in einem jar/cache-Ordner vorhanden ist und nicht im aktuellen Bibliothekssuchpfad.

Unter Windows konnte ich dieses Problem durch die Vorbelastung commonLib in Java lösen, bevor Sie die JNI-Bibliothek zu laden, etwa so:

System.loadLibrary("commonLib"); 
System.loadLibrary("myNativeLib"); 

Doch dieser Ansatz funktioniert nicht auf OS X - dlopen im systemeigenen Code schlägt fehl. dlopen ist anscheinend nicht schlau genug, nicht zu versuchen, die Bibliothek erneut zu laden, wenn sie bereits geladen ist.

Gibt es eine plattformübergreifende Möglichkeit zum Packen und Laden nativer Bibliotheken, die von anderen nativen Bibliotheken in Java Web Start abhängen?

+0

Enthalten die Gläser alle beteiligten Eingeborenen? –

+0

Ja, das habe ich überprüft. –

Antwort

1

Ich konnte einen (hässlichen) Workaround finden. Der Trick ist, die abhängigen Bibliotheken (commonLib) auf eine einfache Ressource jar zu packen und in die jnlp Datei hinzufügen:

... 
<resources os="Windows"> 
    <jar href="native/deps-windows.jar" /> 
</resources> 
<resources os="Linux"> 
    <jar href="native/deps-linux.jar" /> 
</resources> 
<resources os="Mac OS X"> 
    <jar href="native/deps-osx.jar" /> 
</resources> 
... 

Schritt zwei ist es, diese Ressourcen mit Hilfe von Java in ein temporäres Verzeichnis zu extrahieren:

String tmpDir = System.getProperty("java.io.tmpdir"); 
if (!tmpDir.endsWith("/") && !tmpDir.endsWith("\\")) 
    tmpDir += "/"; 
String resource = "commonDir.dll"; // Adjust accordingly to current OS, omitted for brevity 
InputStream is = loader.getResourceAsStream(resource); 
if (is == null) { 
    // Handle error - resource not found 
    return; 
} 
try { 
    FileOutputStream os = new FileOutputStream(tmpDir + resource); 
    byte[] buffer = new byte[1024*1024]; 
    int len = is.read(buffer); 
    while (len != -1) { 
     os.write(buffer, 0, len); 
     len = is.read(buffer); 
    } 
    os.close(); 
    is.close(); 
    System.out.println("Extracted " + resource + " to " + tmpDir); 
} catch(IOException ex) { 
    // Handle the exception - cannot write to temp directory 
    System.out.println("Could not extract resource " + resource + " to " + tmpDir + ": " + ex.getMessage()); 
} 

Schritt 3 informiert entweder die native JNI-Bibliothek über den vollständigen Pfad der extrahierten Abhängigkeit oder legt temporär das aktuelle Verzeichnis auf das temporäre Verzeichnis tmpDir fest, lädt die JNI-Bibliothek und setzt sie zurück. Dies ist ein Problem für sich - in Java ist es schwierig, das aktuelle Arbeitsverzeichnis zu ändern. Sie können es lösen, indem Sie eine andere kleine Dienstprogramm-JNI-Bibliothek erstellen, die das von C tut, obwohl [1].

Verwandte Themen