## HTTPリクエストの処理

featに関連付けられたHTTPリクエストはすべてActionServletクラスが処理します。ActionServletはクライアントから送信されたリクエストURIを分解してフィーチャー、コマンドを特定し、コマンドへ処理を委譲します。

### コマンド

#### コマンドクラス

コマンドはロジックを処理して適切なレスポンスの選択を行うコンポーネントです。Commandクラスを継承する必要があります。

    public class SimpleCommand extends Command {

        public String execute(ContextAccessor acc) throws FeatException {
            return "goto";
        }

    }

コマンドクラスはexecuteメソッドをオーバーライドしなければなりません。executeメソッドで必要なロジックを実行し、結果をリクエストやセッションの属性として保存します。

コマンドはフィーチャー設定ファイルのcommand要素で定義します。上記のSimpleCommandクラスを使った宣言は以下のようになります。

    <commamd
        name="hello"
        class="SimpleCommand"
        response="goto=hello"
    />

#### リクエストパラメータ

StrutsにはActionFormクラスがあり、リクエストパラメータはActionFormに入れられますが、featにはActionFormクラスはありません。リクエストパラメータはCommandクラスにセットされます。このため、コマンドクラスにはパラメータに応じてsetterメソッドを作っておく必要があります。リクエストパラメータはプリプロセスの実行が終わった後でコマンドインスタンスにセットされます。

リクエストパラメータの値の検証はプリプロセス、またはコマンドクラスのexecuteメソッド内部で行います。プリプロセスで行う場合はHttpServletRequestオブジェクトから直接値を取り出します。コマンドオブジェクトに値がセットされるときに型の変換が行われるので、生の入力値を検証する場合はプリプロセスに検証コードを書きます。

#### レスポンスクラスへの情報の受け渡し

コマンドはレスポンスを選択するための文字列を返しますが、もっとたくさんの情報を返したいこともあります。この場合、ContextAccessorクラスのインスタンスを使ってセッションやリクエストに属性をセットします。

一般的なサーブレットフレームワークの機構を使うので、JSPやfeat以外のテンプレートエンジンを使う場合でも問題なく値の受け渡しが出来ます。

#### マルチスレッド

コマンドインスタンスはリクエストごとに生成されます。複数のリクエストが同時に走っていてもコマンドはスレッドセーフで実行されます。しかし、コマンドからアクセスするモデル層や各種のリソースはそれぞれスレッドに対して安全かどうか注意を払う必要があります。

####

### プリプロセス

#### プリプロセスクラス

プリプロセスはコマンド実行前にコマンドの事前条件を検証するコンポーネントです。PreProcessクラスを継承する必要があります。

    public class RequiredParams extends PreProcess {

        public boolean examine(Command command, String[] params, ContextAccessor acc) {
            boolean pass = true;
            HttpServletRequest req = acc.getRequest();
            for(int i=0; i<params.length; i++) {
                String p = req.getParameter(params[i]);
                if ( p == null || p.length() == 0 ) {
                    acc.getFeatureErrors().add(new ValidationError(
                            params[i], "必須項目" + params[i] + "が入力されていない",
                            ValidationError.NULL_ERROR));
                    pass = false;
                }
            }
            return pass;
        }
    }

プロプロセスはのexamineメソッドで事前処理を実行します。コマンドの事前条件が満たされなかったときはfalseを返します。 2番目のStringの配列はリクエストパラメータではありません。これはcommand要素のpre-process属性で指定されたパラメータが入ります。

    <command name="add"
             class="accumulator.AddCommand"
             response="success = sum"
             error-page="error"
             pre-process="require(num1, num2)" />

この例の場合、{"num1", "num2"}がparamsに渡されます。

プリプロセスはフィーチャー設定ファイルのpre-process要素で定義します。

    <pre-process name="require" class="feat2.preprocess.RequiredParams" continue="false" />

プリプロセスではリクエストパラメータをコマンドにセットする前の生のデータを検証することができます。文字列からプロパティの型への変換によって失われてしまう情報もこの段階では残っていますので、ユーザの入力について詳細なエラーを生成することができます。

$Id: request.html 220 2007-07-16 10:32:15Z sugimotokenichi $