2013-07-21 55 views
7

我正在使用Java Web Start啓動依賴某些第三方本機庫的Java應用程序。這些本地庫隨後使用LoadLibrary/dlopen加載另一個本地庫(commonLib)作爲它們的依賴項。Java Web Start - 使用另一個本地依賴項加載本地依賴項

當不使用Web Start時,當本地庫位於同一目錄中時,一切都按預期工作。

Web Start的,但是,需要本機庫被裝在一個jar文件,並在JNLP文件中引用的,我做到了:

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

本機庫加載罰款,但他們無法加載的依賴commonLib - C++ LoadLibrary/dlopen調用失敗,因爲該文件存在於當前庫搜索路徑中的某個jar/cache文件夾中。

在Windows上,我能夠在Java中嘗試加載JNI庫,像這樣通過前預加載commonLib解決這個問題:

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

然而,這種方法並沒有在OS X上運行 - 本地代碼中的dlopen失敗。 dlopen顯然不夠聰明,如果它已經加載,不會嘗試再次加載庫。

是否有跨平臺的方式來打包和加載依賴於Java Web Start中其他本機庫的本機庫?

+0

罐子是否包含所有涉及的土着? –

+0

是的,雙重檢查。 –

回答

1

我能找到一個(醜陋的)解決方法。訣竅是要包了依賴庫(commonLib),以一個簡單的資源罐子並將其添加到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> 
... 

第二步是使用Java這些資源解壓縮到一個臨時目錄:

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

步驟3要麼通知本機JNI庫關於提取依賴項的完整路徑,要麼暫時將當前目錄設置爲臨時目錄tmpDir,加載JNI庫並將其設回。這本身就是一個問題 - 在Java中很難改變當前的工作目錄。你可以通過創建另一個小實用程序JNI庫來解決這個問題,這個JNI庫可以通過C來完成[1]。