バージョン依存性を解決するための 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 メールを読み込む コマンドラインを解析する