Subsections


7 評価と考察

1 評価の概要

4章で挙げた達成目標を,以下に再掲する.

  1. リクエスタは,プロバイダの内部情報を取得できなければならない.
  2. リクエスタは,プロバイダの内部動作を制御できなければならない.
  3. リクエスタ・プロバイダ間の通信プロトコルは,Webサービス技術の枠組でシームレ スに利用可能なものでなければならない.

これらの目標を達成できているか,以下の操作をトレースすることで評価する.

1 クラスオブジェクトの解析とシグニチャの検証

次に述べるビヘイビアシグニチャの検証プロセスを実現できるだ けのシグニチャ情報を入手できることを確認する. その後,特定のビヘイビアに対し,先頭にクラス名およびビヘイビア名の 出力,最後に引数の型および値の出力を行うコードを挿入する. これは,正常シナリオにおいて,達成目標の1, 2を検証する.

2 例外のディスパッチ

異常シナリオにおいて,達成目標の1, 2を検証する.ただし,例外 処理は異常シナリオの回復を目的としているので,プロバイダの動 作に副作用が生じるような制御の改変は控えるべきである.

3 Webサービスプロトコルによる通信の検証

達成目標の3を検証すべく,SOAPメッセージングによる本システムの制御を試み る.Messengerモジュールは,SOAPメッセージを正確にエンコードまたはデコードし, 本システムとリクエスタを仲介できなければならない.

上記の項目について本システムを検証すべく,実際に実行中のサービスに対して 本システムによる制御を試みた.

評価実験では,サービスの要求呼び出しに相当するメソッドに対して以下の操作 を行う.

  1. メソッド呼び出し前にコードをフックし,引数の値をリクエスタに出力 する.
  2. メソッド呼び出し後にコードをフックし,戻り値の値をリクエスタに出 力する.
  3. 例外が発生した場合は,Message Dispatcherにディスパッチする.

以下に,実験に用いたサービスであるCalculatorServiceのコードを示す. このサービスは,任意の演算子を用いて2項演算を行うcomputeというメ ソッドを公開する.サポートされていない演算子を指定された場合は,例外をス ローする.上述の操作は,computeメソッドに対して実行される.

public class CalculatorService {

  private static HashMap<String, Operator> operatorMap;

  static {
    operatorMap = new HashMap<String, Operator>();
    operatorMap.put("+", new PlusOperator());
    operatorMap.put("plus", new PlusOperator());
    operatorMap.put("-", new PlusOperator());
    operatorMap.put("minus", new PlusOperator());
  }

  // 抽象的な演算子クラス.サブクラスで2項演算を実装する
  abstract static class Operator{
    private String name;
    private String symbol;
    Operator(String name, String symbol){
      this.name = name;
      this.symbol = symbol;
    }
    abstract int operate(int x, int y);
  }

  // 加算演算子
  Static Class PlusOperator extends Operator{
    PlusOperator(){
      super("plus", "+");
    }
    int operate(int x, int y){
      return x + y;
    }
  }

  // 減算演算子
  static class MinusOperator extends Operator{
    MinusOperator(){
      super("minus", "-");
    }
    int operate(int x, int y){
      return x - y;
    }
  }

  // 演算子を指定して2項演算
  public int compute(int x, int y, String operator){
    if(!operatorMap.containsKey(operator))
      throw new UnsupportedOperationException("\"" +
    operator + "\" is not supported.");
    else{
      int retval = doCompute(x, y, operatorMap.get(operator));
      return retval;
    }
  }

  private int doCompute(int x, int y, Operator op){
    return op.operate(x, y);
  }
}

2 評価結果

CalculatorServiceに対して前述の操作を行い,本システムによってコー ドが期待通りに変換されていることを確認した.また,変換後のコードが本章の 冒頭に挙げた達成目標を満たすように動作することを確認し,機能性とその限界に ついて評価を行った.以下,それぞれについて詳細を述べる.

1 本システム適用後のコード

変換されたcomputeメソッドは,以下のソースコードと等価なバイトコー ドに変換された(コメントは除く).メソッドの呼び出し前後と例外処理に,意図 した通りの処理が組み込まれている.

public class CalculatorService {
  public int compute(int x, int y, String op) {
    MessageDispatcher dispatcher = controller.getMessageDispatcher();
    dispatcher.write("Method: setValue, x = " + x + , y = " + y);
  try{
    // サポートされていない演算子はエラーで例外処理
    if(!operatorMap.containsKey(operator))
      throw new UnsupportedOperationException("\"" +
        operator + "\" is not supported.");
    else{
      int retval = doCompute(x, y, operatorMap.get(operator));
      dispatcher.write("Method: compute, retval = " + retval);
      return retval;
  }catch(Exception ex){
    dispatcher.exec(ex);
    dispatcher.forward(ex);
  }
}

2 達成目標の評価

1 クラスオブジェクトの解析

実験結果より,ビヘイビアのシグニチャを取得できることを確認した.しか し,ビヘイビア間の関係までは解析できていない.

例えば,あるビヘイビアとそのビヘイビア内から呼び出される他のビヘイビアのみ に着目し解析対象に指定する,といった使い方はできない.なぜなら,ビヘイビ アのボディは解析しないので,ビヘイビア呼び出しの一覧が取得できないからで ある.現状では呼び出されるタイミングでビヘイビア名を出力するコードをす べてのビヘイビアに挿入して,メッセージ内容を元に呼び出し順序を追跡するな ど,実行時に得られる情報から解析しなければならない.

したがって,無差別にビヘイビアの振る舞いをダンプするような使い方は可能で あるが,呼び出しの連鎖に含まれるビヘイビアのみを選択することはできない. より精度の高い情報を得るためには,ビヘイビアのボディを静的解析してコール グラフを作成する必要がある.詳細は考察で述べる.

2 ビヘイビアシグニチャの検証

ポートタイプのクラスオブジェクトが持つビヘイビアは,privateメソッド等も含めて, すべての引数と戻り値を検証できた.

この結果は,リクエスタサイドでプロバイダの振る舞いに対する事前条件および事後 条件を記述できるということを意味する[20].このことは,プロバイダで定義さ れた両条件を満たした上で,更にリクエスタのテスト要件に適した条件に絞りこ めるという有用性をもたらす.

3 例外のディスパッチ

異常シナリオを追跡すべく,例外オブジェクトのスタックトレースをメッセー ジバッファに追加する機能をディスパッチャに組み込み,ディスパッチャを有効 にして故意に例外を発生させたところ,例外連鎖の原因となったクラス名とスタッ クトレースを得られた.

Webサービスは例外をサポートしており,WSDLでfault要素としてカス タム例外を定義しておくことで,ポートタイプで発生した例外をリクエスタに送 信できる.しかし,例外をスローしたクラスやスタックトレースなどの情報は削 られてしまう.本システムを用いれば,例外オブジェクトをWebサービスフレー ムワークが処理してSOAPメッセージ化する前にディスパッチするので,無劣化の Java例外オブジェクトとして独自に処理可能である.

3 考察

本システムでは,ビヘイビア呼び出しの前後に任意のテストコードをフックす ることで,リクエスタサイドによるプロバイダ内部情報の取得および制御を実現 した.この手法によって得られるプロバイダへの干渉能力とリクエスタによるテ スト要件定義能力について,考察を以下に述べる.


1 テスト要件に関係する内部情報の選定

内部情報の取捨選択は,基本的にはリクエスタのニーズに依存するため,完全に 機械的に決定することはできないと考える.しかし,着目すべきサービスインタ フェースに関係する情報のみに限定することは可能である.ある程度内部情報を 絞り込み,かつ依存関係を明らかにすることで,リクエスタによる内部情報の選 定を効果的に支援できる.

テスト要件に必要な内部情報のみを選定するためには,着目するサービスが呼 び出すビヘイビアの一覧が必要である.単純な方法であれば,すべてのビヘイビ アに対して呼び出し時にシグニチャを出力するようなコード断片を挿入し,実際 にサービスを要求して出力を解析すればよい.しかし,この方法ではすべてのビ ヘイビア呼び出しを完全に網羅できるとは限らない.ビヘイビアの相互関係を完 全に明らかにするためには,クラスオブジェクトを静的解析してコールグラフを 作成する必要がある.コールグラフとは,関数の呼び出し関係を有向エッジで結 び付けたグラフである.

ただし,実行時に決定される呼び出し関係は,静的に作成したコールグラフでは 把握できない.また,SOAPメッセージングなど本システムの解析対象に含まれな いRPCも,呼び出し関係とは見なされない.

前者については,実行時に生成したコールグラフで補えばよい.この場合,まだ ロードされていないコードは対象とならないが,そのようなコードは解析対象と なるポートタイプにとって重要でないと判断できるので,大きな問題にはならな いと考える.

後者は,言語仕様外のRPCを扱うための拡張が必要となる.この実現手法につい ては本システムの問題領域から外れるので,ここでは議論しない.

2 リクエスタによるテスト要件の実現

Meyerは「契約による設計」(Design by Contract.以下DbCと呼称)の概念を提唱した [20].DbCは契約プログラミングとも呼ばれ,コードが満たすべき仕様を プログラムとして記述することで,設計の頑健性を高める手法である.

DbCでは,関数の呼び出し前後で満たすべき条件をそれぞれ事前条件,事後条 件と呼称し,プログラムとして記述する.これは,関数の仕様をプログラムとし て明文化することと同義である.

本システムの評価では,ビヘイビアの前後に引数や戻り値をチェックするコード を挿入し,検証に成功した.これは,リクエスタがプロバイダの内部動作に対 する事前条件,事後条件を表明できることを意味する.すなわち,プロバイダの 設計者による事前条件,事後条件を満たす範囲内で,リクエスタが意図する仕様 を条件として追加することで,より精緻なテスト要件が実現できるというこ とである.

例えば,あるビヘイビアの引数または戻り値が,プロバイダが意図した規約には適合して いたとしても,リクエスタ全体の振る舞いにおける部分動作としては不適切であ るというケースが考えられる.このような状況では,リクエスタ側が意図しない値は論理的な バグとみなし,実行時エラーとしてプロバイダに処理させるように,本システム を用いて事前または事後条件を更に制限すればよい.特に非公開ビヘ イビアに関してはプロバイダの処理系に処理と検証を任せざるを得ないので,本 システムを用いることではじめてプロバイダ内部に独自のテスト要件を織り込 むことが可能になる.

なお,DbCでは事前条件,事後条件の他に,クラス,メソッド,フィールドの不 変性を保証する契約として,不変条件の概念を提唱している.本システムにおいて リクエスタによる不変条件の表明を実現するためには,クラスやメンバを監視す るようなコードを実行時動的コード変換技術を用いて挿入すればよい.しかし, 一般にリクエスタはビヘイビアの振る舞いが及ぼす影響について知りたいのであっ て,ビヘイビアの不変性を保証できたところで有用性は少ないと考えられる. したがって,本システムでは不変条件をサポートしていない.

MITSUBAYASHI Shin 2007-03-14