以下の2つのクラスのサブクラスを作成しなければいけません.
AbstractProcessorでは,実際の変換処理を行い, 指定された場所へ変換後のクラスファイルを出力します. なお,変換の前に前処理用のメソッドが呼び出され, 変換が全て終わったあと,後処理用のメソッドが呼び出されます.
AbstractProcessorServiceでは,処理器のメタ情報を定義します. 処理器の作成者,作成者の所属団体,また,処理器がどのようなパラメータを受け取るのか, そのパラメータの初期値を適切に返すように実装します.
AbstractProcessorクラスとAbstractProcessorServiceクラスは1対1の対応関係を持ちます. 一方,AbstractProcessorオブジェクトはAbstractProcessorServiceオブジェクトに対して複数存在できます. AbstractProcessorオブジェクトがいくつ存在しようと,対応するAbstractProcessorServiceは1つです. もちろん,別の処理(処理B)を行う処理器の場合は,別のAbstractProcessorServiceオブジェクトが存在します.
以下の3つのメソッドを実装しなければいけません. また,処理結果をSummaryオブジェクトにまとめて返します.
メソッド名 | 返り値の型 | 説明 |
prepare | void | Processorの初期化処理のため,呼び出されます. |
perform | void | Processorの処理を行います. |
summarize | void | Processorの後処理のため,呼び出されます. |
以下,それぞれのメソッドが行うこと,処理結果の出力方法について説明します.
初期化処理を行います.このメソッドにはArgumentsが渡されます. 渡されたArgumentsに沿って処理を行うよう初期化しなければいけません.
実際に変換を行うメソッドです.このメソッドは2つの引数を受け取ります. TargetSourceとDestinationです.
TargetSourceは入力の集合を表します.zipやjar, ディレクトリ内のクラスファイルの集合を抽象化するクラスです. 処理器が入力元を意識しなくても良いようになっています. TargetSourceは複数のProcessTargetを持ちます. ProcessTargetの列挙はTargetSourceのiteratorメソッドで得られます.
ProcessTargetは1つのファイルを表します. ファイルの種類はProcessTargetのgetTypeメソッドで判定できます. また,ファイルの内容はgetSourceメソッドが返すInputStreamから読み取れます.
Destinationは出力先を抽象化します.zipファイル,jarファイル, ディレクトリを区別せず出力できます. outputメソッドにクラス名もしくはファイル名を渡せば,それに対応した OutputStreamが返されます. 返されたOutputStreamにクラスファイルを出力すれば,適切に処理されます.
処理中に確保したメモリの解放などの終了処理を行います.
処理結果はSummaryオブジェクトにまとめられ出力されます. Summaryオブジェクトは自動的に作成されるため,エントリを追加することで処理結果をまとめます. エントリはキーと値のペアで表されます.キーも値も文字列型で表されます. キーは階層構造としても表せ,階層は「.(ドット)」で区切ります.
AbstractProcessorServiceクラスを継承したクラスを作成します. 継承したクラスでは以下のメソッドを実装し,適切なオブジェクトを返さなくてはいけません.
メソッド名 | 返り値の型 | 説明 |
getProcessorName | String | この処理器の名前を文字列で返します. |
getDescription | String | この処理器の説明を文字列で返します. |
createProcessor | Processor | 対応する処理器オブジェクトを生成して返します. |
createProvider | Provider | この処理器の著者情報を返します. |
createDefaultArguments | Arguments | この処理器のパラメータの初期値を返します. |
適当な場所にrydeen.spi.ProcessorServiceという名前のファイルを作成します. 内容は上で作成したAbstractProcessorServiceを継承したクラスの完全修飾名 (パッケージ名を含むクラス名.最後に.classは必要ありません)を書きます. 1行に1クラスとしてください.
作成した処理器, SPIとその関連クラスを全て含むjarファイルを作成します. 上で作成したサービスデスクリプタはMETA-INF/services/に置いてください. その後,作成したjarファイルをクラスパスに含めてRydeenを実行すれば自動的に作成したクラスが認識されます.
ここでは,サンプルとして,何も処理しないNopProcessorをサンプルとして作成します. パッケージはrydeen.plugins.nopとします.
処理器のクラスを作成します.このクラスはAbstractProcessorを継承し, AbstractProcessorクラスのサブクラスの作成 で記したメソッドを実装します.
NopProcessorでは何も処理を行わないので,prepareメソッド,summarizeメソッドは何も行いません.
package rydeen.plugins.nop; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import rydeen.AbstractProcessor; import rydeen.Arguments; import rydeen.Destination; import rydeen.ProcessorException; import rydeen.ProcessTarget; import rydeen.TargetSource; public class NopProcessor extends AbstractProcessor{ public NopProcessor(NopProcessorService service){ super(service); } @Override public void prepare(Arguments args){ // do nothing.... } @Override public void perform(TargetSource source, Destination dest) throws ProcessorException{ for(ProcessTarget target: source){ try{ InputStream in = target.getSource(); OutputStream out = dest.output(target.getName()); putEntry("target", target.getName()); int data; while((data = in.read()) != -1){ out.write(data); } in.close(); out.close(); } catch(IOException e){ throw new ProcessorException(e); } } } @Override public void summarize(){ // do nothing.... } }
AbstractProcessorServiceクラスを継承してProcessorServiceの実装クラスを作成します. 実装しなければならないメソッドは上で記した5つのメソッドです.
getProcessorNameメソッドはASCII文字列で返してください. getDescriptionは今のところ,Localeは無視できます. getProviderメソッドで,作成者情報を隠しておきたい場合はProvider.UNKNOWNを返すことができます.
createProcessorメソッドは処理器が必要になったときに呼び出されます. このメソッドでは毎回新たなオブジェクトを作成してください. なぜなら,1セッションの間に同じ処理器が実行される場合があり, 同じ処理器でも与えるパラメータが異なる場合があります. それらは同一のオブジェクトでは区別できないため,新たなオブジェクトを必要とするためです.
createDefaultArgumentsは最初の1度だけ呼び出されるメソッドです. このサービスクラスが提供する処理器のパラメータとその初期値を表すオブジェクト Argumentsを作成し,返してください.受け取るパラメータが何もなければ, このサンプルのように単純にArgumentsオブジェクトを作成し,返してください.
package rydeen.plugins.nop; import java.net.URL; import java.net.MalformedURLException; import rydeen.Arguments; import rydeen.Processor; import rydeen.spi.AbstractProcessorService; import rydeen.utils.Author; import rydeen.utils.Organization; import rydeen.utils.Provider; public class NopProcessorService extends AbstractProcessorService{ @Override public String getProcessorName(){ return "nop"; } @Override public String getDescription(){ return "何も処理を行わない処理器"; } @Override public Processor createProcessor(){ return new NopProcessor(this); } @Override public Provider createProvider(){ return Provider.RYDEEN_PROVIDER; } @Override public Arguments createDefaultArguments(){ return new Arguments(); } }
rydeen.spi.ProcessorServiceファイルに以下の内容を書きます.
rydeen.plugins.nop.NopProcessorService
以下の構成でjarファイルを作成します.
root -+- rydeen ---- plugins ---- nop -+- NopProcessor.class | | | +- NopProcessorService.class +- META-INF -+- MANIFEST.MF | +- services --- rydeen.spi.ProcessorService
作成したjarファイルをRydeenのlibディレクトリに置くと起動時に読み込みます. 以下のコマンドを入力し,最後にnopが表示されればデプロイできています.
$ rydeen.sh --help