<!-- -*- mode:text coding:euc-jp -*-
   $FML: bootloader.sgml,v 1.14 2008/08/18 13:21:42 fukachan Exp $
-->


<chapter id="bootloader">
	<title>
	バージョン依存性を解決するための fml ブートローダ
	</title>

<para>
&fml8; には、
インストールされている fml のバージョン依存性を解決するために、
本章で述べるブートストラップ過程があります。
<screen>
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
</screen>
</para>


<sect1 id="bootloader.example.distribute">
	<title>
	例: 配送処理の場合
	</title>

<para>
たとえば配送処理の場合、
loader から次々とモジュールが呼ばれていく様子は次のようになります。
</para>

<para>
/usr/local/libexec/fml/distributre
(の実体は /usr/local/libexec/fml/loader)
は
/usr/local/etc/fml/main.cf を読みこみ、
fml_version 変数から使うべきライブラリのバージョンを決めます。
たとえば fml_vesrion が 8.0.0 となっていれば、
/usr/local/lib/fml/8.0.0/
以下にあるライブラリを使うといった具合です。
</para>

<para>
@INC を再設定した後、
loader は FML::Process::Switch をロードし、
$0 (プロセス名)を調べます。
プロセス名から自分の仕事は配送処理なので、
FML::Process::Distribute クラスをロードすればよいことを理解します。
このクラスをロードし、配送処理に移ります。
ここで、プロセス名とロードするべきクラスの対応関係は 
/usr/local/etc/fml/defaults/バージョン/modules
(例 /usr/local/etc/fml/defaults/8.0.0/modules)
に定義されています。
</para>

<para>
こういった処理は、
見かけ上
FML::Process::Flow::ProcessStart()
という関数が制御しています。
ProcessStart() が引数として
FML::Process::Distribute 
オブジェクトを渡され、
FML::Process::Distribute
オブジェクトを実行していくという流れになります。
</para>

</sect1>


<sect1 id="bootloader.classes">
	<title>
	FML::Process:: クラスの階層構造
	</title>

<para>
<screen>
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  ... その他 ...
</screen>

</para>
</sect1>


<sect1 id="bootloader.classes2">
	<title>
	プロセス実行時の様子
	</title>

<itemizedlist>

   <listitem>
	<para>
	[/usr/local/libexec/fml/loader (wrapper)の実行]
	</para>
	
	<para>
	この段階では、まだ &fml8; Perl モジュール群に制御が移っていません。
	このプログラムは、loader 内の関数 Bootstrap() を実行します。
	</para>
	
	<para>
	distribute など libexec/ 以下にあるプログラム群は、
	どれも、この loader へのシンボリックリンクです。
	/usr/local/libexec/fml/ 以下を参照してください。
	</para>
   </listitem>

   <listitem>
	<para>
	[loader 内 Bootstrap() 関数の実行]
	</para>
	
	<para>
	/usr/local/etc/fml/main.cf を読み込み、
	実行するべき fml のバージョンを知ります。
	また、
	main.cf の値から
	@INC (Perl のライブラリサーチパス)を再設定し、
	読み込むべきライブラリのバージョン依存性を解決します。
	default_config.cf.{ja,en} はバージョン依存ですので、
	設定ファイルを読み込む前に、
	この段階でバージョンを評価しなければいけません。
	</para>

	<para>
	@ARGV (実行されたプログラムの引数)を評価し、
	どのＭＬの config.cf (設定ファイル)群を読み込むべきか？を判断します。
	</para>
   </listitem>

   <listitem>
	<para>
	このあと、ようやく
	FML::Process::Switch
	(バージョン依存)クラスをロードします。
	</para>

	<para>
	Bootstrap2() および ProcessSwitch() を実行し、
	FML::Process::Flow 経由で、
	配送用、コマンドメール用などの各プロセスへ制御を移していきます。
	</para>
	
	<para>
	この時点で、
	どのモジュール(例: FML::Process::Distribute)
	をロードするのかは分かっています。
	FML::Process::Distribute オブジェクトなどは、
	FML::Process::Flow の関数を呼び出す際に引数として渡されています。
	</para>

   </listitem>

   <listitem>
	<para>
	FML::Process::Flow 経由で、	
	各モジュール(例: FML::Process::Distribute)
	のメソッドを呼び出します。
	</para>
	
	<para>
	FML::Process::Flow の中には、
	どのように &fml8; プロセスを実行するかが規格化/定義されています。
	おおむね、どのプロセスも
<screen>
$process = new FML::Process::なになに;
$process->prepare($args);
$process->verify_request($args);
$process->run($args);
$process->finish($args);
</screen>
	を実行していきます。
	のため、各プロセスは、
	それぞれについて適当なメソッドを
	「FML::Process::なになに」
	以下のクラスに用意する必要があります。
	ダミーでもいいので、全メソッドの定義が必要です。
	</para>
    </listitem>
</itemizedlist>
</sect1>


<sect1 id="bootloader.resolv.mlxxx">
	<title>
	議論: ml_name と ml_domain の値はどこで解決するのが正しいか？
	</title>

<para>
現在は
「FML::Process::なになに」
の prepare() メソッドあたりで解決しています。
</para>

<para>
以下、内部構造についての走り書き/おぼえがきです。
一応、こういった構造を考慮して、
prepare()
に持ってきています。 
<screen>
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
			メールを読み込む
			コマンドラインを解析する
</screen>
</para>

</sect1>


</chapter>
