新たな処理機を作成するに当たり,Rocinante の中で要となるクラスがいく つか存在します.まずはそのクラスの役割を述べます.
| BytecodeProcessor | 実際のバイトコード処理器のためのインターフェース. |
| AbstractBytecodeProcessor | BytecodeProcessor で定義されるメソッドのうち,各処理器で共通となる実装を与えた抽象処理器. |
| FilterBytecodeProcessor | 処理器で処理を行った後,別の処理器にクラスファイルを渡したい場合に用いるクラス. |
| Summary | バイトコード処理がどのように行われたのか,要約を表すクラス.バイトコード処理器の終了処理呼び出し時に作成されます. |
| FormattedSummary | このクラスから得られる PrintWriter に対して要約を書くことができる Summary クラス. |
| Arguments | バイトコード処理器に渡される引数. |
| BytecodeException | バイトコードに対する処理が失敗した場合に投げられる例外クラス. |
| BytecodeListener | バイトコード処理に対するリスナインターフェース. |
多くの場合,処理器を作成する際に出てくるクラスは AbstractBytecodeProcessor,FilterBytecodeProcessor,Arguments そして, FormattedSummary の 4 つのクラスとなるでしょう.
DonQuixote プラグインは全て BytecodeProcessor インターフェースを implements します.このインターフェースは以下のメソッドを持ちます.
package jp.cafebabe.donquixote.rocinante.BytecodeProcessor;
/**
* Java bytecode processing filter.
*
* @author Haruaki TAMADA
* @version $Revision: 1.1 $ $Date: 2006/03/17 07:49:00 $
*/
public interface BytecodeProcessor{
public void setName(String name);
public String getName();
public void setDescription(String description);
public String getDescription();
public void setArguments(Arguments parameter);
public Arguments getArguments();
public void prepare() throws BytecodeException;
public void perform(org.apache.bcel.classfile.JavaClass target,
java.net.URL loadFrom) throws BytecodeException;
public Summary finish() throws BytecodeException;
public void addBytecodeListener(BytecodeListener listener);
public void removeBytecodeListener(BytecodeListener listener);
}
実装の簡易化のため,AbstractBytecodeProcessor が用意されています.こ のクラスは BytecodeProcessor に基本的な実装を与え,またサブクラスのた めに,いくつかのメソッドを追加しています.追加したメソッドは initialize, summarize の 2 つです.処理器の初期化,そして,Summary の 作成は新たに加えられたこれらのメソッドの中で行うようにしてください.
しかし,基本的に,AbstractBytecodeProcessor を継承させた場合, BytecodeProcessor に用意されている perform メソッドのみを実装すれば処 理器として動作します.Summary も何も要約を行わない Summary のインスタ ンスを返します.
ただし,処理器に合わせた Summary を返す方が望ましいでしょう.
このクラスでは,prepare が呼び出されたときには,必ず,getArguments, getName, getDescription は有効な値を返すようになっています.
このクラスは処理器によって処理された後のクラスファイルを別の処理器に 渡したい場合に継承させる BytecodeProcessor です.この処理器で新たな JavaClass を作成した後,スーパークラスの protected フィールドである processor.perform を実行する必要があります.また,BytecodeProcessor を 受け取るコンストラクタを用意する必要があります.
例を以下に示します.
public class SomeFilterProcessor extends FilterBytecodeProcessor{
public SomeFilterProcessor(BytecodeProcessor nextProcessor){
super(nextProcessor);
}
public void perform(JavaClass target, URL loadFrom) throws BytecodeException{
:
JavaClass modifiedTarget = ....
// super.processor(modifiedTarget, loadFrom);
// or
processor.perform(modifiedTarget, loadFrom);
}
protected Summary summarize(){
FormattedSummary summary = new FormattedSummary(getName());
PrintWriter out = summary.getWriter();
out.println(...); // print summary
out.close();
return summary;
}
}
FilterBytecodeProcessor の場合,例のように,perform の最後に, processor.perform を呼び出す必要があります.そうしなければ,次に処理が 渡されないため,不具合が起きる可能性があります.
処理内容の要約を表すためのインターフェースです.例えば,名前難読化を 用いて,ある名前を別の名前に変換する処理器の場合,元の名前と変換後の名 前のマッピングを示す必要があります.また,文字列を暗号化する処理器の場 合,暗号化のキーや暗号アルゴリズムなどを示すことが望まれます.
そのような情報をこの Summary を使って出力することが可能です.多くの場 合,FormattedSummary が使われることが多いでしょう.FormattedSummary は PrintWriter を返す getWriter メソッドを持ち,その PrintWriter に対して 文字を書き出すことで Summary が作られます.
また,独自の Summary を用意することもできます.そのときには, AbstractSummary を用いると便利です.Summary として,基本的な機能は既に 与えられているため,printSummary メソッドのみを実装すれば独自の Summary が作成できます.