| MAP | PageMixer ドキュメント > チュートリアル > PageMixer の利用 > 効率的な組み合わせ | << | >> |
本節では、 PageMixer における効率的なフィルタの組み合わせ方に関して説明します。
本節におけるクラス図を以下に示します。
色づけされているのが本節で定義するクラスで、 それ以外は PageMixer において定義済みです。
本節におけるオブジェクト図を以下に示します。
本チュートリアルでは、 クラスは全てクラス名のみで表記されています。 完全な名称は以下の通りです。
| 表記 | 完全名 |
|---|---|
| ConsumerContext | jp.ne.dti.lares.foozy.pagemixer.mixer.ConsumerContext |
| Filter | jp.ne.dti.lares.foozy.pagemixer.mixer.Filter |
| FilterPipeline | jp.ne.dti.lares.foozy.pagemixer.mixer.FilterPipeline |
| HTMLSymbolSet | jp.ne.dti.lares.foozy.pagemixer.HTMLSymbolSet |
| SequenceHybridFilter | jp.ne.dti.lares.foozy.pagemixer.mixer.SequenceHybridFilter |
| SequenceTrimFilter | jp.ne.dti.lares.foozy.pagemixer.mixer.SequenceTrimFilter |
| SequenceWatcher | jp.ne.dti.lares.foozy.pagemixer.mixer.SequenceWatcher |
| Token | jp.ne.dti.lares.foozy.pagemixer.Token |
| TrimFilter | jp.ne.dti.lares.foozy.pagemixer.mixer.TrimFilter |
| 表記 | 完全名 |
|---|---|
| AlreadyLoginFilter | pagemixer.filter.AlreadyLoginFilter |
| Bootstrap | pagemixer.filter.Bootstrap |
| Trim | pagemixer.filter.AlreadyLoginFilter.Trim |
| UsernameAttrInsetFilter | pagemixer.filter.UsernameTextInsetFilter |
単純にフィルタを接続して使用した場合、 全てのフィルタが全ての Token 列を処理することになります。
しかし、 それらフィルタのいくつかは Token 列の殆ど全てに対して興味を示しません。 例えば、 HTML ページにおける "ログイン" 機能に関するフィルタは、 Token 列の "ログイン" 機能の部分にしか興味がありません。
10 のフィルタに 5000 の Token
から構成されるシーケンスを処理させた場合、
処理の総量は 5,000 * 10 = 50,000 となります。
しかし、そのうちの3つだけにシーケンス全体を処理させ、
残りの7つには、それらが興味のある 100 の Token
だけを処理させた場合、
処理の総量は (5,000 * 3) + (100 * 7) = 15,700 となり、
およそ 70% の処理コストを削減することが出来ます。
フィルタの "木目細かさ" を維持することは、 機能が多くのフィルタによって構成されることを意味し、 それ故に処理コスト低減が必要とされます。
SequenceHybridFilter の拡張フィルタを効率的に組み合わせるために、
PageMixer フレームワークは
"SequenceHybridFilter" クラスを提供しています。
このクラスのインスタンスは、
SequenceWatcher および
Filter で構築されます。
指定された Filter には、
SequenceWatcher
によって認識された部分シーケンスだけが提供されます。
FilterPipeline を用いることで、
部分シーケンスを複数のフィルタに提供することができます。
HTML ページにおける "ログイン" 機能向けのフィルタ群を、 効率的に組み合わせるフィルタは以下のようになります。
public class AlreadyLoginFilter
extends SequenceHybridFilter
{
final static
private HTMLSymbolSet SET = HTMLSymbolSet.SET;
final static
private String ATTR_VALUE = "Auth-AlreadyLogin";
////////////////////////////////////////
public AlreadyLoginFilter(Object keyLogin){
super(new SequenceWatcher.NameAttr(SET.SPAN,
SET.CLASS,
ATTR_VALUE),
create(keyLogin));
}
// 非 staic メソッドは
// 基底クラスのコンストラクタ起動には不適切
static
private Filter createFilter(Object keyLogin){
FilterPipeline pipeline = new FilterPipeline();
pipeline.push(new UsernameTextInsetFilter(keyLogin));
pipeline.push(new Trim(keyLogin));
return pipeline;
}
}
SequenceHybridFilter の拡張"AlreadyLoginFilter" は、
"<span class="Auth-AlreadyLogin">" および
"</span>" で挟まれた部分シーケンスを、
"create" メソッドにおいて
FilterPipeline に追加されたフィルタ群へと供給します。
上記部分シーケンスが、全体の 10% から構成されているとすると、
AlreadyLoginFilter こそシーケンス全体の 100% を処理しますが、
"ログイン" 機能用のフィルタ群は、
シーケンス全体の 10% だけを処理することになります。
結果、(100 + 10 * 2)/(100 * 2) = 120/200 = 0.6 から、
今回定義したクラスによって 40% の処理コストが削減されます。
より多くのフィルタを HybridSequenceFilter と組み合わせることで、 より多くの低減を得ることができます。 例えば、 10 のフィルタを併用した場合、 (100 + 10 * 10)/(100 * 10) = 200/1000 = 0.2 から 80% の処理コストが低減できます。
UsernameTextInsetFilter に関しては、
"シーケンスへのデータはめ込み"
節において説明済みです。
"Trim" フィルタは、
まだ説明していない "TrimFilter" の派生クラスです。
TrimFilter は、
与えられたシーケンス全体を刈り込むフィルタです。
SequenceTrimFilter.Whole と
TrimFilter の違いは、
SequenceWatcherによって認識された部分シーケンスを刈り込むか、
シーケンス全体を刈り込むか、という点だけです。
以上で必要なものが全て揃いました。 実行コードは以下のようになります (詳細は AlreadyLoginFilter を参照してください)。
try{
// ユーザ名設定/取得用のキー
final Object key = "Auth.Login";
// ユーザ名
final String name = "foozy";
Bootstrap bootstrap =
new Bootstrap.Default(filename)
{
protected void prepare(ConsumerContext context)
{
// "login" はユーザ名のコンテキストへの
// 設定の有無を保持する
if(login){
// ユーザ名をコンテキストに設定
context.setValue(key, name);
}
}
};
AlreadyLoginFilter filter =
new AlreadyLoginFilter(key);
// フィルタの適用
bootstrap.execute(filter);
}
catch(Exception e){
e.printStackTrace(System.err);
}
入力用のサンプル HTML ファイルは、
配布物中の "src/demo/servlet/war/WEB-INF/page/demosite"
配下にある
"auth.ja.html" です。
| MAP | PageMixer ドキュメント > チュートリアル > PageMixer の利用 > 効率的な組み合わせ | << | >> |