JavaBeans入門’(その3)
Beansは、JavaBeansの仕様で記述されたクラス(ファイル)である。JavaBeansの仕様で書いておくことによって、Builderで内部の値を変更したり、どのようなイベントを生成するか(イベントセット)を知ることができる。これを行うのがJava Beansのintrospection機能である。
Wiringとは
さて、JavaBeansでのプログラミングの中心となるのが、Wiring、すなわちそれぞれのJavaBeansのイベントを通じての関連づけをする部分である。Builder内で、部品Aと部品Bについて、マウスをつかって結びつける操作を行う。すなわち、この操作では部品Aで発生したイベントをBにつたえて、部品Bのメソッドを呼び出すようにする。ここで、JavaのGUIのプログラミングについて思い出してみよう。ボタンbuttonAがactionEvent というイベントセットをもち、それをHelloLabelがうけとって、”hello”というメッセージを表示する場合、おこなわなくてはならないことは、HelloLabelをActionListenerとしてインタフェースをつくっておき、これを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.
さらに、BeanBoxでadaptorにtargetを設定したり、adaptorをListenerとして設定したりするにはreflection機能を利用してクラスのメソッドを呼び出している。
1に関しては、beansbox/tmp/sun/beanbox/というdirectoryに、__Hookup_????という名前のクラスのプログラムを作り、これがadaptorになっている。これをコンパイルし、できたクラスファイルを動的にロードする。2に関しては、以前reflectionのところで説明したとおり、java.lang.reflectのMethodクラスに定義されているinvokeメソッドをつかって、setTargetやaddActionListenerを呼び出せばよい。
Appletの生成
BeanBoxでは適当に部品を配置し、wiringしてできたプログラムをAppletとしてsaveすることができる。これによって、たとえば、appletの名前をMyAppletとすると、所定のdirectory ( ./tmp/MyApplet)に、以下のファイルが作られる。
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.instantiateはnewの働きをするのであるが、これはもしも”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コマンドでも作ることができる。
自分が作ったBeanをBeanBoxなどのBuilerにもっていくためにはJARファイルにしておかなくてはならない。但し、単なるJARファイルではなくて、
Name: クラスファイル名
Java-Bean:
true
Name: クラスファイル名
Java-Bean:
true
…
というどれがBeanであるかというファイルを作って、これをmanifestとして作らなくてはならない、このファイルをmanifest.tmpとすると、
%jar cfm JARFILE
manifest.tp *.class
として作る。mはmanifestファイルを指定するオプションである。これをクラスパスに設定しておけば、builderで使えるようになる。(但し、beanBoxでは、../jarsしかみていないようだ)
これで、javaBeansは終わり、次からはJini+RMIによる分散プログラミング環境に移る。
次回5月30日は、3時15分から(5時限のみ)