分析SWT3.3加載原生庫的過程
SWT3.3 M4(2006年12月15日)新增加的功能之一是自動加載原生庫,特別是從SWT的Jar文件中加載原生庫的功能,大大方便了我們發(fā)布基于SWT的Java程序。SWT是怎么實(shí)現(xiàn)這個功能的呢? 理解其中的原理后,您也可以在您自己的程序中實(shí)現(xiàn)類似的功能。
SWT負(fù)責(zé)加載原生庫的方法是Library類的loadLibrary (String name)
static
{
Library.loadLibrary( " swt " );
}
Library.loadLibrary( " swt " );
}
Library.loadLibrary()做的第一件事在庫名上加上版本號,比如swt-win32-3325。
如果您的原生庫文件名不包含版本號,您可以省略這一步。
String version = System.getProperty ("swt.version");
if (version == null) {
version = "" + MAJOR_VERSION;
/* Force 3 digits in minor version number */
if (MINOR_VERSION < 10) {
version += "00"; //$NON-NLS-1$
} else {
if (MINOR_VERSION < 100) version += "0";
}
version += MINOR_VERSION;
/* No "r" until first revision */
if (REVISION > 0) version += "r" + REVISION;
}
libName1 = name + "-" + Platform.PLATFORM + "-" + version;
libName2 = name + "-" + Platform.PLATFORM
if (version == null) {
version = "" + MAJOR_VERSION;
/* Force 3 digits in minor version number */
if (MINOR_VERSION < 10) {
version += "00"; //$NON-NLS-1$
} else {
if (MINOR_VERSION < 100) version += "0";
}
version += MINOR_VERSION;
/* No "r" until first revision */
if (REVISION > 0) version += "r" + REVISION;
}
libName1 = name + "-" + Platform.PLATFORM + "-" + version;
libName2 = name + "-" + Platform.PLATFORM
第二件事是加上操作系統(tǒng)相關(guān)的庫擴(kuò)展名,比如Windows的.dll, Unix/Linux的.so.
調(diào)用System.mapLibraryName (libName1).
mappedName1
=
System.mapLibraryName (libName1);
mappedName2 = System.mapLibraryName (libName2);
mappedName2 = System.mapLibraryName (libName2);
然后按順序從swt.library.path和java.library.path指定的目錄下尋找。如若沒有成功,
并且沒有設(shè)置swt.library.path,那么再找一下java.io.tmpdir指定的目錄。要是還沒有成功,Library將嘗試
將SWT的Jar文件中的原生庫解壓到swt.library.path目錄下或者java.io.tmpdir目錄下。
/*
Try loading library from java library path
*/
f (load (libName1)) return ;
if (mapName && load (libName2)) return ;
/* Try loading library from the tmp directory if swt library path is not specified */
if (path == null ) {
path = System.getProperty ( " java.io.tmpdir " );
path = new File (path).getAbsolutePath ();
if (load (path + SEPARATOR + mappedName1)) return ;
if (mapName && load (path + SEPARATOR + mappedName2)) return ;
}
/* Try extracting and loading library from jar */
if (path != null ) {
if (extract (path + SEPARATOR + mappedName1, mappedName1)) return ;
if (mapName && extract (path + SEPARATOR + mappedName2, mappedName2)) return ;
}
/* Failed to find the library */
throw new UnsatisfiedLinkError ( " no " + libName1 + " or " + libName2 + " in swt.library.path, java.libary.path or the jar file " );
f (load (libName1)) return ;
if (mapName && load (libName2)) return ;
/* Try loading library from the tmp directory if swt library path is not specified */
if (path == null ) {
path = System.getProperty ( " java.io.tmpdir " );
path = new File (path).getAbsolutePath ();
if (load (path + SEPARATOR + mappedName1)) return ;
if (mapName && load (path + SEPARATOR + mappedName2)) return ;
}
/* Try extracting and loading library from jar */
if (path != null ) {
if (extract (path + SEPARATOR + mappedName1, mappedName1)) return ;
if (mapName && extract (path + SEPARATOR + mappedName2, mappedName2)) return ;
}
/* Failed to find the library */
throw new UnsatisfiedLinkError ( " no " + libName1 + " or " + libName2 + " in swt.library.path, java.libary.path or the jar file " );
extract (path+SEPARATOR+mappedName1, mappedName1)將mappedName1從Jar中解壓到
path+SEPARATOR+mappedName1。最后如果還是沒有成功,甩出一個UnsatisfiedLinkError。
整個過程有意思的只是extract()方法,下面來看看extract
static
boolean
extract (String fileName, String mappedName)
{
FileOutputStream os = null ;
InputStream is = null ;
File file = new File(fileName);
try {
if ( ! file.exists ()) {
is = Library. class .getResourceAsStream ( " / " + mappedName);
if (is != null ) {
int read;
byte [] buffer = new byte [ 4096 ];
os = new FileOutputStream (fileName);
while ((read = is.read (buffer)) != - 1 ) {
os.write(buffer, 0 , read);
}
os.close ();
is.close ();
if ( ! Platform.PLATFORM.equals ( " win32 " )) {
try {
Runtime.getRuntime ().exec (
new String [] { " chmod " , " 755 " , fileName} ).waitFor();
} catch (Throwable e) {}
}
if (load (fileName)) return true ;
}
}
} catch (Throwable e) {
try {
if (os != null ) os.close ();
} catch (IOException e1) {}
try {
if (is != null ) is.close ();
} catch (IOException e1) {}
}
if (file.exists ()) file.delete ();
return false ;
}
FileOutputStream os = null ;
InputStream is = null ;
File file = new File(fileName);
try {
if ( ! file.exists ()) {
is = Library. class .getResourceAsStream ( " / " + mappedName);
if (is != null ) {
int read;
byte [] buffer = new byte [ 4096 ];
os = new FileOutputStream (fileName);
while ((read = is.read (buffer)) != - 1 ) {
os.write(buffer, 0 , read);
}
os.close ();
is.close ();
if ( ! Platform.PLATFORM.equals ( " win32 " )) {
try {
Runtime.getRuntime ().exec (
new String [] { " chmod " , " 755 " , fileName} ).waitFor();
} catch (Throwable e) {}
}
if (load (fileName)) return true ;
}
}
} catch (Throwable e) {
try {
if (os != null ) os.close ();
} catch (IOException e1) {}
try {
if (is != null ) is.close ();
} catch (IOException e1) {}
}
if (file.exists ()) file.delete ();
return false ;
}
Library.class.getResourceAsStream ("/" + mappedName)返回指向Jar根目錄下mappedName文件的
InputStream.個人感覺,extract寫得有點(diǎn)亂,if套著if,if套著try,當(dāng)然并不是很糟糕,本身這是一個比較簡單的函數(shù)。
在我自己的程序中,重寫了extract(改名為extractAndLoad),相對來說要清爽一些,請大家比較。
通過上面的分析,我們可以很簡單實(shí)現(xiàn)我們自己的loadLibrary
import
org.eclipse.swt.SWT;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
/**
* The method loadLibrary load a native library in the order
* from java.library.path, os.library.path, tmpdir and from jar.
*
* @author pan
*/
public class Library {
static final String SEPARATOR = System.getProperty( " file.separator " );
public static void loadLibrary(String name) {
// Try loading library from os library path
String path = System.getProperty( " os.library.path " );
if (path != null ) {
path = new File(path).getAbsolutePath();
if (_load(System.mapLibraryName(path + SEPARATOR + name)))
return ;
}
// Try loading library from java library path
if (_load(name))
return ;
// Try loading library from the tmp directory if os library path is not specified
if (path == null ) {
path = System.getProperty( " java.io.tmpdir " );
path = new File(path).getAbsolutePath();
if (_load(System.mapLibraryName(path + SEPARATOR + name)))
return ;
}
// Try extracting and loading library from jar
if (path != null
&& loadFromJar(System.mapLibraryName(path + SEPARATOR + name),
System.mapLibraryName(name)))
return ;
// Failed to find the library
throw new UnsatisfiedLinkError( " no " + name
+ " in java.libary.path, os.library.path or jar file " );
}
private static boolean _load(String libName) {
try {
if (libName.indexOf(SEPARATOR) != - 1 ) {
System.load(libName);
} else {
System.loadLibrary(libName);
}
return true ;
} catch (UnsatisfiedLinkError e) {
}
return false ;
}
private static boolean loadFromJar(String outFileName, String libName) {
try {
return extractAndLoad(outFileName, libName);
} catch (Throwable e) {
}
return false ;
}
private static boolean extractAndLoad(String outFileName, String libName)
throws Throwable {
int read;
byte [] buf = new byte [ 4096 ];
InputStream is = null ;
FileOutputStream os = null ;
File file = new File(outFileName);
if (file.exists())
file.delete();
if ( ! file.exists()) {
try {
os = new FileOutputStream(file);
is = Library. class .getResourceAsStream( " / " + libName);
if (is == null || os == null )
return false ;
while ((read = is.read(buf)) != - 1 )
os.write(buf, 0 , read);
} finally {
if (os != null )
os.close();
if (is != null )
is.close();
}
if ( ! SWT.getPlatform().equals( " win32 " )) {
Runtime.getRuntime().exec(
new String[] { " chmod " , " 755 " , outFileName }).waitFor();
}
return _load(outFileName);
}
return false ;
}
}
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
/**
* The method loadLibrary load a native library in the order
* from java.library.path, os.library.path, tmpdir and from jar.
*
* @author pan
*/
public class Library {
static final String SEPARATOR = System.getProperty( " file.separator " );
public static void loadLibrary(String name) {
// Try loading library from os library path
String path = System.getProperty( " os.library.path " );
if (path != null ) {
path = new File(path).getAbsolutePath();
if (_load(System.mapLibraryName(path + SEPARATOR + name)))
return ;
}
// Try loading library from java library path
if (_load(name))
return ;
// Try loading library from the tmp directory if os library path is not specified
if (path == null ) {
path = System.getProperty( " java.io.tmpdir " );
path = new File(path).getAbsolutePath();
if (_load(System.mapLibraryName(path + SEPARATOR + name)))
return ;
}
// Try extracting and loading library from jar
if (path != null
&& loadFromJar(System.mapLibraryName(path + SEPARATOR + name),
System.mapLibraryName(name)))
return ;
// Failed to find the library
throw new UnsatisfiedLinkError( " no " + name
+ " in java.libary.path, os.library.path or jar file " );
}
private static boolean _load(String libName) {
try {
if (libName.indexOf(SEPARATOR) != - 1 ) {
System.load(libName);
} else {
System.loadLibrary(libName);
}
return true ;
} catch (UnsatisfiedLinkError e) {
}
return false ;
}
private static boolean loadFromJar(String outFileName, String libName) {
try {
return extractAndLoad(outFileName, libName);
} catch (Throwable e) {
}
return false ;
}
private static boolean extractAndLoad(String outFileName, String libName)
throws Throwable {
int read;
byte [] buf = new byte [ 4096 ];
InputStream is = null ;
FileOutputStream os = null ;
File file = new File(outFileName);
if (file.exists())
file.delete();
if ( ! file.exists()) {
try {
os = new FileOutputStream(file);
is = Library. class .getResourceAsStream( " / " + libName);
if (is == null || os == null )
return false ;
while ((read = is.read(buf)) != - 1 )
os.write(buf, 0 , read);
} finally {
if (os != null )
os.close();
if (is != null )
is.close();
}
if ( ! SWT.getPlatform().equals( " win32 " )) {
Runtime.getRuntime().exec(
new String[] { " chmod " , " 755 " , outFileName }).waitFor();
}
return _load(outFileName);
}
return false ;
}
}
然后把您的原生庫打在Jar里面,用Library.loadLibrary加載原生庫,而不是System.loadLibrary,這樣您就
把原生庫隱藏在您的Jar里面了。
轉(zhuǎn)載請保留http://www.aygfsteel.com/xilaile/archive/2007/03/23/105706.html
posted on 2007-03-23 02:10 gr8vyguy 閱讀(5473) 評論(1) 編輯 收藏 所屬分類: Java