2013-07-21 11 views
7

Używam Java Web Start, aby uruchomić aplikację Java, która zależy od bibliotek natywnych innych firm. Te natywne biblioteki następnie ładują inną natywną bibliotekę (commonLib) jako swoją zależność za pomocą LoadLibrary/dlopen.Java Web Start - załaduj rodzimą zależność z inną rodzimą zależnością.

Gdy nie korzystasz z Web Start, wszystko działa zgodnie z oczekiwaniami, gdy natywne biblioteki znajdują się w tym samym katalogu.

Web Start wymaga jednak rodzime biblioteki mają być pakowane w pliku jar i odwołuje w pliku jnlp, co robiłam:

<!-- 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> 

rodzime biblioteki załadować w porządku, ale nie udaje im się załadować ich uzależnienia commonLib - wywołanie funkcji C++ LoadLibrary/dlopen nie powiodło się, ponieważ plik znajduje się w folderze jar/cache, a nie w bieżącej ścieżce wyszukiwania biblioteki.

W Windows, udało mi się rozwiązać ten problem przez pre-loading commonLib w Javie przed próbuje załadować biblioteki JNI, tak:

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

Jednak takie podejście nie działa na OS X - dlopen w natywnym kodzie nie działa. dlopen najwyraźniej nie jest wystarczająco inteligentny, aby nie spróbować ponownie załadować biblioteki, jeśli jest już załadowany.

Czy istnieje międzyplatformowy sposób pakowania i ładowania bibliotek rodzimych zależnych od innych bibliotek natywnych w Java Web Start?

+0

Czy słoiki zawierają wszystkich tubylców? –

+0

Tak, sprawdź to. –

Odpowiedz

1

Udało mi się znaleźć (brzydkie) obejście. Sztuką jest, aby spakować bibliotek zależnych (commonLib) do prostego słoiku zasobów i dodać go do pliku jnlp:

... 
<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> 
... 

Krok drugi jest wydobycie tych zasobów przy użyciu języka Java do tymczasowego katalogu:

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()); 
} 

Krok 3 to poinformowanie natywnej biblioteki JNI o ​​pełnej ścieżce do wyodrębnionej zależności lub tymczasowe ustawienie bieżącego katalogu w katalogu tymczasowym tmpDir, załadowanie biblioteki JNI i jej ponowne ustawienie. Jest to problem sam w sobie - w Javie trudno jest zmienić bieżący katalog roboczy. Możesz go rozwiązać, tworząc inną małą bibliotekę JNI narzędzia, która robi to z C, chociaż [1].

Powiązane problemy