2008年4月27日日曜日

Native library loading framework for Applet (Native Capable)

NyARToolkitのデモAppletを作る際、JMFやJOGLなど実行時にネイティブライブラリを必要とするAPI利用のためにクラスローダ等を実装したのですが、全体をフレームワーク化したので公開します。
ライセンスはLGPLとしています。

(2008/5/8 追記) テンポラリファイルが削除されないバグを修正しました。
File.deleteOnExit関数がWindows上では正しく機能しない既知のバグ
によるものです。



Applet、Java Web Startまたはスタンドアロンアプリケーションにおいて、ネイティブライブラリを可能な限り同じコードで利用できることを目的として作成したフレームワークです。(JWSにはネイティブを扱う機構が存在します)
動作には、nativecapable.jarのほかにjavassist.jar、ant.jarが必要です。
(バイナリ&ソース&サンプルに同封)

何かに使って見た際にでも感想などいただけると幸せです^^

以下に使用方法を説明します。

1. NativeCapableModuleの実装

ネイティブライブラリを利用したいモジュールはNativeCapableModuleインタフェースを実装します。NativeCapableModuleインタフェースでは4つのメソッドが定義されています。

       //モジュールの初期化処理を記述します
      public boolean initModule();
       //モジュールの停止及び破棄処理を記述します
      public boolean destroyModule();
       //GUIアプリケーションの場合、
       //最上位に配置されるコンポーネントを返す処理を記述します
      public Component getRootComponent();
       //モジュールの開始処理を記述します
       public boolean startModule();

NativeCapableModuleの実装クラスはApplet及びスタンドアロンアプリケーションとして利用することができます。

2.Appletとして実装する

Appletとして実装する場合はNativeCapableAppletクラスを継承して利用します。
NativeCapableAppletクラスはJAppletクラスを継承し、NativeCapableインタフェースを実装しています。
Java3DTestAppletをもとに説明します。(バイナリ&ソース&サンプルに含まれる)

public class Java3DTestApplet extends NativeCapableApplet {
    public void init() {
               //Moduleの生成を行うインスタンスを生成します
             NativeCapableModuleBuilder builder = new NativeCapableModuleBuilder(
           this, "java3d.Java3DTestModule");

               //ネイティブライブラリを利用するクラスのロードについて設定します -  ①
             Collection col = new HashSet();
             col.add("javax.media.j3d");
              builder.setTargetPackages(col);
             builder.setDelegateTargets(false);

               //Moduleインスタンスを生成します
              NativeCapableModule module = builder.newModule();
               //モジュールの初期化
              module.initModule();
               //モジュールからAppletに追加するコンポネントを取得して追加します
              add(module.getRootComponent());

               //必要に応じてstartやdestroyを呼び出します。
              //module.startModule();
              //module.destroyModule();
}

① クラスのロードについて
NativeCapableModuleBuilder#setDelegateTarget(boolean)メソッドによりターゲット指定されたパッケージに属するクラスをNativeCapableClassLoaderでロードするか、指定されたもの意外をロードするかを設定することができます。
NyARToolkitのデモであるJavaSimpleLiteAppletでは次のように使用しています。

               Collection col = new HashSet();
             boolean dTargets = true;
              if (!dTargets) {
               col.add("javax.media.");
               col.add("com.sun.opengl.");
               col.add("jp.nyatla.");
                col.add("com.sun.media.");
                col.add("jp.ac.kyutech.ai.ylab.shiva");
             } else {
               col.add("java.");
                col.add("javax.swing.");
                col.add("sun.reflect.");
             }
            builder.setTargetPackages(col);
             builder.setDelegateTargets(dTargets);

3.スタンドアロンアプリケーションとして実装する

Appletの場合とほぼ同じですが、NativeCapableApplicationを利用します。
public class Java3DTestApplication {
    public static void main(String[] args) throws Exception {
           NativeCapableApplication nca = new NativeCapableApplication();
           NativeCapableModuleBuilder builder = new NativeCapableModuleBuilder(
         nca, "java3d.Java3DTestModule");

            Collection col = new HashSet();
            col.add("javax.media.j3d");
           builder.setTargetPackages(col);
            builder.setDelegateTargets(false);

           final NativeCapableModule module = builder.newModule();
            module.initModule();

           nca.add(module.getRootComponent());
           nca.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            nca.addWindowListener(new WindowAdapter() {
               public void windowClosing(WindowEvent e) {
                  module.destroyModule();
              }
           });
           nca.setBounds(100, 100, 640, 480);
           nca.setVisible(true);

           module.startModule();
}

4.ネイティブライブラリを配備

以下に説明する設定ファイルで指定したディレクトリに必要なネイティブライブラリを配備します。

ネイティブライブラリ設定ファイル(os.xml)
OSごとに利用するライブラリの設定をos.xmlに記述します。os.xmlはNativeCapableModuleのクラスファイルが存在するディレクトリルートに配備します。
配備例

記述例
<?xml version="1.0" encoding="UTF-8" ?>
<libraries>
<library arch="x86" name="Windows" path="native/x86/windows" />
<library arch="x86" name="Linux" path="native/x86/linux" />
</libraries>

archプロパティにはアーキテクチャをnameプロパティはOSの名前を指定します。
それぞれつぎのJavaプログラムで取得される文字列と前方一致を行います。
  System.getProperty("os.name");
  System.getProperty("os.arch");
pathプロパティにはネイティブライブラリの位置をos.xmlファイルからの相対パスで指定します。

5.AppletやJavaWebStart(JWS)として公開する場合の注意点
ネイティブライブラリを実行時に展開するためにサンドボックス外へのアクセスが必要となります。
そのため、AppletやJWSにする場合はJARファイルに署名を行う必要があります。
署名つきJARファイルの作成やJWSでのパーミッション設定などはここでは省略します。

0 件のコメント: