gr8vyguy@Blogjava

          分析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-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

          第二件事是加上操作系統(tǒng)相關(guān)的庫擴(kuò)展名,比如Windows的.dll, Unix/Linux的.so.
          調(diào)用System.mapLibraryName (libName1).
          mappedName1  =  System.mapLibraryName (libName1);
          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 " );


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

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

          然后把您的原生庫打在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

          評論

          # re: 分析SWT3.3加載原生庫的過程 2007-03-23 02:51 BeanSoft

          就是先解壓在系統(tǒng)臨時目錄里了, 然后再加載. 有時候會有問題, 例如你的 dll 需要相對路徑的時候就不能用這種方法了, 倒是可以解壓縮在一個固定的相對位置, 退出時清空.

          不過 SWT 這個新特性的確是人性化的多了... 做軟件多考慮用戶, 是王道啊...  回復(fù)  更多評論   

          <2007年3月>
          25262728123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          導(dǎo)航

          統(tǒng)計(jì)

          公告

        1. 轉(zhuǎn)載請注明出處.
        2. msn: gr8vyguy at live.com
        3. 常用鏈接

          留言簿(9)

          隨筆分類(68)

          隨筆檔案(80)

          文章分類(1)

          My Open Source Projects

          搜索

          積分與排名

          最新評論

          主站蜘蛛池模板: 抚松县| 宝应县| 山东| 日照市| 伊春市| 西平县| 武城县| 芜湖县| 芷江| 岳西县| 梨树县| 丰镇市| 湘西| 郸城县| 尚义县| 湟中县| 利辛县| 贡觉县| 辽中县| 丽江市| 任丘市| 新密市| 容城县| 兰考县| 赤水市| 娄烦县| 清新县| 舟曲县| 唐河县| 雅江县| 北辰区| 石景山区| 光泽县| 高密市| 上饶县| 建湖县| 溧阳市| 芜湖县| 天峻县| 惠来县| 偃师市|