JavaBeans入門(その3)

 Beansは、JavaBeansの仕様で記述されたクラス(ファイル)である。JavaBeansの仕様で書いておくことによって、Builderで内部の値を変更したり、どのようなイベントを生成するか(イベントセット)を知ることができる。これを行うのがJava Beansintrospection機能である。

Wiringとは

 さて、JavaBeansでのプログラミングの中心となるのが、Wiring、すなわちそれぞれのJavaBeansのイベントを通じての関連づけをする部分である。Builder内で、部品Aと部品Bについて、マウスをつかって結びつける操作を行う。すなわち、この操作では部品Aで発生したイベントをBにつたえて、部品Bのメソッドを呼び出すようにする。ここで、JavaGUIのプログラミングについて思い出してみよう。ボタンbuttonAactionEvent              というイベントセットをもち、それをHelloLabelがうけとって、”hello”というメッセージを表示する場合、おこなわなくてはならないことは、HelloLabelActionListenerとしてインタフェースをつくっておき、これをbuttonAのリスナーとして登録することである。

class buttonA { …

  buttonA(HelloLabel label) {

     … addActionListener(label); …

  } }

class HelloLabel implements ActionListener { …

   actionPerformed(ActionEvent ev) {  … showHello(); /*“hello”を表示*/ }

}

class Exec {

  public static void main(String argv[]) {

    HelloLabel l = new HelloLabel();

    new buttonA(l):

}

ここで、Execは初期設定をするためのmainを持つクラスである。しかし、このようなプログラムをするには、プログラムの中にイベント処理のためのコードが埋め込まれてしまっている。このようなコードが埋め込まれていては、「部品」として他の用途につかうことができないということになってしまう。

Adapterクラスの利用

このような問題に対処するためには、デザインパターンのところで解説したAdapterというものをつかう。

class buttonA { … }

class HelloLabel { … }

class Adapter implements ActionListener {

  private HelloLabel target;

  public void setTarget(HelloLabel t){ target = t; }

  public void actionPerformed(ActionEvent ev) {  target.showHello(); }

}

class Exec {

   public static void main(String argv[]){

     Hello l = new HelloLabel();

     buttonA botton = new buttonA();

     Adapter adapter = new Adapter();

     adapter.setTarget(l):

     button.addActionListener(adapter);

}

つまり、イベントを受け取るためのAdapterという仲介をするオブジェクトをつくって、イベントの橋渡しをさせることによって、元のコードにリスナーを作らなくてもよくなる。Exec.mainではこのadapterをつくってこれをListenerにしている。(実際にはexec.mainはない)

BuilderでのWiringの処理

 さて、このような動作をBuilderではどうしているのか。簡単なBuilderであるBeanBoxでは、Wiringに対して以下の処理を行っている。

1.        AdapterクラスのプログラムをBeanBoxの中で実行中に生成し、コンパイルして、それを動的にロードして実行している。

2.        さらに、BeanBoxadaptortargetを設定したり、adaptorListenerとして設定したりするにはreflection機能を利用してクラスのメソッドを呼び出している。

1に関しては、beansbox/tmp/sun/beanbox/というdirectoryに、__Hookup_????という名前のクラスのプログラムを作り、これがadaptorになっている。これをコンパイルし、できたクラスファイルを動的にロードする。2に関しては、以前reflectionのところで説明したとおり、java.lang.reflectMethodクラスに定義されているinvokeメソッドをつかって、setTargetaddActionListenerを呼び出せばよい。

Appletの生成

BeanBoxでは適当に部品を配置し、wiringしてできたプログラムをAppletとしてsaveすることができる。これによって、たとえば、appletの名前をMyAppletとすると、所定のdirectory ( ./tmp/MyApplet)に、以下のファイルが作られる。

  1. MyApplet.html: appletをテストするためのHTMLファイル
  2. MyApplet_files: ここには生成されたappletのプログラムとdataが入る。
  3. MyApplet.jar: MyApplet_filesJARにしてまとめたもの。
  4. その他の必要なbeansの入ったJARファイル

JARファイルは複数のクラスをまとめたファイルである。テスト用のHTMLファイルには、以下のように記述されている。

<applet

    archive="./myApplet.jar,./support.jar

        ,./mytools.jar

    "

    code="Hello"

    width=390

    height=492

>

通常、Appletには、codebase=として、クラスファイルのあるwebサーバ側のdirectory指定するが、ここではarchiveとして必要なJARファイルを指定している。

 生成されたAppletのプログラムは、MyApplet_files/Hello.javaにある。通常のアプレットとは違って、コンストラクタのところでほとんどの処理をしている。ここから呼ばれるinitContentsでは、Beans.instantiatenewの働きをするのであるが、これはもしも”OurButton”という名前で、serializationされたオブジェクトがあった場合、そのオブジェクトを元にインスタンスを作る操作をするメソッドである。ここでは、newと同じである。その後、BeansBoxで設定したプロパティをセットしている。

次に呼ばれているのは、addConnectionsである。ここでは、_hookup_???として作ったAdaptorを生成し、実際にプログラムのなかで、targetをセットし、Listenerとして登録するコードを出している。もはや、BeanBoxではないので、実際のコードを出力すればいいことに注意。

その他のメソッドとして、このappletをオブジェクトとして書き出したり、読み込んだりするメソッドreadObject/writeObjectがある。

 

 

JARファイルとBeanの作り方

 javaのクラスのファイルは、jarというコマンドでJARファイルにしておくことができる。実際のクラスのあるdirectoryに対するパスを設定する代わりに、このファイルをクラスパスに設定しておけばこの中にあるクラスファイルが参照されるようになる。jarファイルの作り方は、tarに似ている。クラスのあるdirectoryで、

 % jar –cvf  directory

とすればよい。

実際、jarのファイル形式は、zip形式を使ったものなので、zip/unzipコマンドでも作ることができる。

自分が作ったBeanBeanBoxなどのBuilerにもっていくためにはJARファイルにしておかなくてはならない。但し、単なるJARファイルではなくて、

Name: クラスファイル名

Java-Bean: true

 

Name: クラスファイル名

Java-Bean: true

というどれがBeanであるかというファイルを作って、これをmanifestとして作らなくてはならない、このファイルをmanifest.tmpとすると、

 %jar cfm JARFILE manifest.tp *.class

として作る。mmanifestファイルを指定するオプションである。これをクラスパスに設定しておけば、builderで使えるようになる。(但し、beanBoxでは、../jarsしかみていないようだ)

 

これで、javaBeansは終わり、次からはJini+RMIによる分散プログラミング環境に移る。

 

次回5月30日は、3時15分から(5時限のみ)