バージョン依存性を解決するための fml ブートローダ
&fml8; にはインストールされている fml のバージョン依存性を考慮するため
に、本章で述べるようなブートストラップの過程があります。
fml (libexec/distribute) が boot していく様子
functions class
----------------------------------------
main::Bootstrap() libexec/loader
|
V
main::Bootstrap2() FML::Process::Switch
|
V
ProcessSwitch() FML::Process::Switch
|
|
| switch to ($obj = FML::Process:Distribute)
|
V
ProcessStart($obj,$args) FML::Process::Flow
例: 配送の場合
たとえば配送処理の場合、
loader から次々とモジュールが呼ばれていく様子は次のようになります。
/usr/local/libexec/fml/distributre (の実体
/usr/local/libexec/fml/loader) は /usr/local/etc/fml/main.cf を読みこ
み、fml_version 変数から使うべきライブラリのバージョンを決めます。
たとえば fml_vesrion が current-20010501 となっていたら
/usr/local/lib/fml/current-20010501/ 以下にあるライブラリを使うといっ
たぐあいです。
@INC を再設定した後、
loader は FML::Process::Switch をロードし、
$0 (プロセス名)を調べます。
その名前から自分の仕事は配送処理なので
FML::Process::Distribute クラスをロードし、配送処理に移ります。
なお、プログラム名とクラスの対応関係は
/usr/local/etc/fml/defaults/バージョン/modules
で定義されています。
こういった処理は見かけ上 FML::Process::Flow::ProcessStart() という関数
が制御しています。ProcessStart() が引数として FML::Process::Distribute
オブジェクトを渡され、FML::Process::Distribute オブジェクトを実行して
いくという流れになります。
FML::Process:: クラスの階層構造
FML::Process::Distribute >-|
FML::Process::Command >-|-- FML::Process::Kernel
FML::Process::Mead >-| |
|-use-a FML::Parse
|-use-a FML::Config
|-use-a FML::Log
|-use-a ... その他 ...
プロセス実行時に使われるモジュール群
/usr/local/libexec/fml/loader (wrapper)。
これは Bootstrap() を実行します。
distribute などは、皆この loader へのシンボリックリンクです。
/usr/local/libexec/fml/ 以下を参照してください。
/usr/local/etc/fml/main.cf を読み込み、
fml のバージョンを知ります。
また、main.cf の値から @INC (Perl のライブラリサーチパス)を再設定し、
読み込むべきライブラリのバージョン依存性を解決します。
default_config.cf.{ja,en} はバージョン依存ですので、
設定ファイルを読み込む前に、
この段階でバージョンを評価しなければいけないことに注意してください。
@ARGV (実行されたプログラムの引数 )を評価し、
どのMLの config.cf (設定ファイル)群を読み込むのかを判断します。
次に
FML::Process::Switch
(バージョン依存)クラスをロードします。
Bootstrap2() および ProcessSwitch() を実行し、
配送用、コマンドメール用などの各プロセスへ制御を移します。
この時点で、すでに $0 から、
どのプロセスへ成りかわればいいのかは分かっています。
(ポリモーフィズムの例)
モジュールをダイナミックバインディングし、
該当するプロセスオブジェクトを生成、
そして、プロセスをスタートさせます。
FML::Process::Flow の中に、
どのように fml8 プロセスを実行するかが
定義されています。おおまかには
$process = new FML::Process::なにか;
$process->prepare($args);
$process->verify_request($args);
$process->run($args);
$process->finish($args);
のような実行順です。
各プロセスは、それぞれについて適当なメソッドを
FML::Process:: 以下のクラスで用意する必要があります。
議論: ml_name と ml_domain の値はどこで解決するのが正しいか?
現在では、FML::Process:: の prepare() あたりで解決しています。
以下、内部構造について、2、3の走り書き/おぼえがきを残しておきます。
一応、こういった構造を考慮して、
prepare() メソッドあたりに持ってきているわけです。
main::Bootstrap()
main.cf から fml のバージョン依存性を解く
hints を渡す (CGI のみ)
◎ CGI だけ
嘘の入力がありうる
そのため、loader に hints として
ml_domain や ml_name がハードコードされている。
main::Bootstrap2()
ProcessSwitch()
使うモジュール( Process::なんか )を決める
読み込むべき cf ファイルの決定(なんで?)
ライブラリパスの決定や @INC の修正など
hints を渡す?使う? (CGI のみ?)
ProcessStart($obj, $args)
処理本体のスタート
new
prepare
ml_name と ml_domain の決定
CGI からの入力を解析する
hints を使う?(CGI のみ?)
読み込むべき cf ファイルの決定
parse
メールを読み込む
コマンドラインを解析する