• 検索結果がありません。

第 3 章 Jacross 27

4.1 クラスのタイプに応じた配置方針の決定

第 4 章 実装

この章ではJacrossの実装についての説明を行う。JacrossはAddistantの 文法や機能を参考に類似した設計となっており、さらに前節で説明した

Jacross独自の機能を追加している。大まかに分けると以下の3つの機能

を実装している。

遠隔参照の実装の自動化

アプリケーションセマンティクスの変更に対応する分散Aspect XMLによる分散配置方針の決定

以下では、具体的にこれらの機能をどのように実装したかについて紹介 する。

図4.1: Remote Proxyパターン

で実行出来るようにコード変換されている。(図4.2参照)この配置方針 は、参照者クラスが非可変でかつ、被参照者コードが可変である場合に特 に有効な方針である。一方、1つのホスト上にローカルとリモートで参照 を持ちたい場合には利用する事が出来ない。この配置方針では1つのホス ト上の対象クラスへの参照はローカルか遠隔かどちらか一方に限られる。

4.1.2 Rename

この配置方針では、遠隔配置の対象となるクラスとは別の名前でプロキ シを用意する。なお、Jacrossでは<クラス名>Proxyという名前でプ ロキシクラスを提供する。ここで用意されるプロキシは対象クラスと同じ 構造・同じメソッドを持ちメソッドの中身のみが遠隔実行用に書き換えら れている。遠隔参照を行うコードは、対象クラスを参照している箇所が全 て書き換えられ、<クラス名> Proxyクラスへの参照に置き換えられる。

(図4.3参照)参照の置き換えが必須となる為、参照者クラスが可変でな くてはならない。この配置方針は配置対象となるコードが非可変である場 合に特に有効な方針である。また、この方針でも1つのホスト上からの対 象クラスへの参照はローカルか遠隔かどちらか一方に限られる。

図4.2: Replace

4.1.3 Subclass

この配置方針では、遠隔配置の対象となるクラスのサブクラスの形でプ ロキシを用意する。Jacrossでは、<クラス名> Proxyという名前で親ク ラスを対象クラスに持つプロキシクラスを提供する。メソッド・構造は親 クラスと同様に作られるが、メソッド呼び出しは遠隔実行が可能なように 中身が置き換えられている。この配置方針は主に1つのホスト上で対象ク ラスへの参照がローカルと遠隔の両方が混在する場合に用いられる。こ の場合、ローカル参照は元の対象クラスをそのまま用い、遠隔参照はサブ クラス化したプロキシをインスタンス化し、そのオブジェクトを用いて遠 隔実行を行う。(図4.4)この配置方針は、他の手法と比較して制約が厳し く、参照者クラスが可変でなくてはならない上、対象クラスも可変でなく てはならなくては適用出来ない場合がある。それは対象クラスが修飾子に

finalを持っていたりメソッドがfinalだったりする場合、それを取り外さ

なくてはならないからだ。また対象クラスのコンストラクタ呼び出しが都 合の悪い副作用を生じる場合、何もしないコンストラクタ呼び出しを追加 しなくてはならない等の変更も必要になる。

図4.3: Rename

図 4.4: Subclass

4.1.4 配置方針のオプション

Jacrossでは上記の3つの方針で遠隔配置を自動化しているが、より詳

細な配置方針を決定するオプションとして、以下の2つの機能を用意して いる。

permethod

メソッド単位での遠隔配置を行う為のオプション。前章で説明したよう に、この配置方針が用いられると対象メソッドのみが遠隔呼び出しされ る。このオプションを用いると、対象オブジェクトはローカルホスト上と 遠隔ホスト上にペアの形で1つずつオブジェクトが生成される。ローカル でのメソッド呼び出しはローカルオブジェクトを通し、遠隔でのメソッド 呼び出しは、リモートで生成されたオブジェクトを通してメソッド呼び出 しを行う。permethodオプションを用いる場合は、状態の反映を行わな いといけないケースがあるため、対象クラス・参照クラスが共に可変であ る事が望ましい。Replaceの場合、対象メソッドは遠隔実行できるように 変更されたコードで置き換わる。またコンストラクタ呼び出しに同様の コンストラクタを用いて遠隔上にオブジェクトを生成するコードが加わ る。ローカルのメソッド呼び出しはそのまま実行され、遠隔のメソッド呼 び出しはペアとして用意された遠隔オブジェクトへの参照を用いて行わ

れる。Renameの場合も同様に対象メソッドのみが遠隔実行できるように

編集された<クラス名>Proxyの名前のプロキシクラスが生成される。

Subclassの場合も同様で対象メソッドのみが遠隔実行されるようなプロ

キシクラスを対象クラスの子クラスとして用意する。

ORB

Jacrossを用いると、ユーザは自分の好きなORBを用いて遠隔実行の

呼び出しを行う事が出来る。オリジナルなORBを用いる場合、Jacross の仕様に基づいた形でORBを定義すればJacrossで用意されているもの と差し替える可能である。Jacrossで用意しているProxyTemplateクラス を継承し、指定のメソッドをオーバーライドする事により実装できる。ま た、あらかじめプロキシジェネレータが用意されているようなORBの場

合、Jacrossはそのプロキシジェネレータの仕様に対応する形でコードを

編集する。現在の実装では、JavaRMIにのみの対応となっている。

4.1.5 具体的なコード変換処理の詳細

遠隔参照の自動化についての具体的なコード変換処理の詳細を説明す

る。Jacrossはバイトコード変換で、これらの遠隔参照の自動化を行って

おりバイトコードレベルAPI(Application Programming Interface)と してJavassist [2, 24, 23]を用いている。Javassistは、Javaの標準APIに 含まれているリフレクション機能 [16]を強化したものであり、プログラ ムの構造を調べるだけではなく、定義を改変する事も出来るライブラリで ある。クラスSampleについて、Javassistを使ってRename方針でプロキ シを生成する流れを説明する。以下はJacross中のProxyGeneratorを抜 粋し、デフォルメしたコードである。

01 CtClass baseclass = pool.get(‘‘Sample’’);

02 CtClass proxyclass

= pool.make(baseclass.getName() + ‘‘_Proxy’’);

03 CtMethod[] basemethods = baseclass.getDeclaredMethods();

04 CtField[] fields = baseclass.getDeclaredFields();

05 CtMethod[] proxymethods = new CtMethod[basemethods.length];

06 CtField[] proxyfields = new CtField[basefields.length];

08 for(int i = 0; i < basemethods.length; i++){

09 proxymethods[i] = makeproxymethod(basemethods[i]);

10 proxyclass.addMethod(proxymethods[i]);}

11 for(int j = 0; j < basefields.length; i++){

12 proxyfields[i] = makefieldmethod(basefield[i]);

13 proxyclass.addField(proxyfields[i]);}

ここで登場するCtClass、CtMethod、CtFieldなどのクラスは、Javassist で用意されているクラスで、リフレクションAPIのClass,Method,Fieldク ラスと類似した作りとなっている。01行目はClassPool型のpoolオブジェ

クトからSampleというクラスのCtClassオブジェクトを取得する処理で

ある。ClassPoolオブジェクトは、クラスを表すCtClassオブジェクトのコ ンテナとなっているオブジェクトである。02行目はSample Proxyという 名前で新たにクラスを生成する処理である。03,04行目ではSampleクラス から全てのメソッドと全てのフィールドを取得し、それぞれCtMethod型、

CtField型の配列に格納する。05,06行目の処理ではプロキシ用にSample クラスのメソッドとフィールドをそれぞれプロキシ化する為に同じサイズ の配列を用意している。09行目は、プロキシのメソッドをSampleのメ ソッドと同等な中身をORBを用いた呼び出しに差し替える処理を行って いる(makeproxymethodはJacross中のProxyGeneratorクラスのメソッ ド)。10行目では、09行目で生成されたCtMethodオブジェクトをプロ

キシを表すCtClassオブジェクトに追加する処理である。CtClassでは、

構造リフレクションを扱う為、addMethodやaddFieldといったメソッド が用意されている。このような構造リフレクションはメモリ上で処理が行 われており、このままの状態であるとクラスファイルには反映されない。

14 proxyclass.writeFile();

そこで明示的に14行目のようにCtClassオブジェクトにwriteFileメソッ ド呼び出しをする事でクラスファイルに変換される。実際のプロキシ生成 には、この他にも親クラスに対する処理やインターフェースに対する処理 なども加わる事になる。

次に既存プログラム中の対象クラスの参照を、生成されたプロキシへの 参照に変更する(Replace方針では必要がない)。javassist.exprパッケー

ジ内にはExprEditorというメソッドの振る舞いを変える機能を持つクラ

スがある。ExprEditorには引数の違うeditメソッドが6つ用意されてい る。このeditメソッドがメソッドの振る舞いを変える為のメソッドで、演 算の種類ごと(メソッドコール、フィールドアクセス、インスタンス生 成)に別々の処理を行う事が出来る。ExprEditorクラス自体は、java.awt パッケージのイベントリスナのアダプタクラスのように何も仕事はしない ので、ユーザは適切にオーバーライドして利用しなくてはならない。

01 CtMethod cm = ...;

02 SampleEditor editor = new SampleEditor();

03 cm.instrument(editor);

---04 public class SampleEditor extends ExprEditor { 05 public void edit(NewExpr n) throws ..{

06 if(n.getClassName().equals(‘‘Sample’’))

07 n.replace(‘‘{System.out.println(‘‘Sample generates’’);

08 $_=$proceed($$);};}’’);

09 }

上の例では、SampleEditorはメソッド内のSampleクラスのインスタンス が生成される時、インスタンス生成をする前にSystem.out.println(“Sample generates”);という式を行うように変更するedit処理を行っている。06行 目の条件にマッチした場合、07行目のreplaceメソッドの中の式に置き 換えられる。replaceメソッドはString型の引数を取り、ここには置換す る為のソースコードを記述する事が出来る。ここで、09行目で行われて いる$ =$proceed($$);という処理はJavassistで用意されている特殊な構

文で、replaceメソッド内で元々呼び出されている処理を表している。以

上のように用意されたSampleEditorを使って01〜03行目の処理を行う

関連したドキュメント