SAStrutsを読む:Struts以降

さっきのつづき。

デバッガでIndexAction#index()にブレークポイント張ってS2RequestProcessor#processからのスタックトレースを見てみる。

(インターセプタの処理略)
satest.action.IndexAction$$EnhancedByS2AOP$$9ac272.index()
(Method.invoke関係略)
org.seasar.framework.util.MethodUtil.invoke(java.lang.reflect.Method, java.lang.Object, java.lang.Object[])
org.seasar.struts.action.ActionWrapper.execute(javax.servlet.http.HttpServletRequest, org.seasar.struts.config.S2ExecuteConfig)
org.seasar.struts.action.ActionWrapper.execute(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
org.seasar.struts.action.S2RequestProcessor(org.apache.struts.action.RequestProcessor)
org.seasar.struts.action.S2RequestProcessor.process(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)

ActionWrapperがディスパッチ本体と見た。
RequestProcessorがActionWrapperのインスタンス見つけて呼ぶ部分はわからないがとりあえずActionWrapperを読んでみる

//ActionWrapper#execute
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
		HttpServletRequest request, HttpServletResponse response)
		throws Exception {
	S2ExecuteConfig executeConfig = S2ExecuteConfigUtil.getExecuteConfig();
	if (executeConfig != null) {
		return execute(request, executeConfig);
	}
	return null;
}

S2ExecuteConfigにはディスパッチ対象となるアクションのメソッドとか入ってる。なぜスタティックメソッドなのかというと、内部ではSingletonS2Container.getComponent使ってHttpServletRequestを取得してるから。

public static S2ExecuteConfig getExecuteConfig() {
	return (S2ExecuteConfig) RequestUtil.getRequest().getAttribute(S2ExecuteConfigUtil.class.getName());
}
public static HttpServletRequest getRequest() {
	return SingletonS2Container.getComponent(HttpServletRequest.class);
}

S2ExecuteConfig取得後実行されるアクション起動のコードはこれ。

protected ActionForward execute(HttpServletRequest request,
		S2ExecuteConfig executeConfig) {
	ActionMessages errors = new ActionMessages();
	List<S2ValidationConfig> validationConfigs = executeConfig
			.getValidationConfigs();
	if (validationConfigs != null) {
		// バリデーション起動部省略
		// まあバリデータ呼んでるだけだと思います
	}
	if (!errors.isEmpty()) {
		return processErrors(errors, request, executeConfig);
	}
	// バリデーション成功したらアクションを呼ぶ
	// ちなみにactionはActionMapping#getAction()で取得
	// nextはアクションの帰り値、すなわち遷移先jspのパス
	String next = (String) MethodUtil.invoke(executeConfig.getMethod(),
			action, null);
	// 必要があればアクションフォーム除去
	if (executeConfig.isRemoveActionForm()) {
		RequestUtil.getRequest().getSession().removeAttribute(
				actionMapping.getActionFormComponentDef()
						.getComponentName());
		RequestUtil.getRequest().removeAttribute(
				actionMapping.getAttribute());
	}
	// リダイレクトの設定
	boolean redirect = executeConfig.isRedirect();
	if (redirect && ActionMessagesUtil.hasErrors(request)) {
		redirect = false;
	}
	// そしてActionForwardを返す
	return actionMapping.createForward(next, redirect);
}

まあそんなもんですね。
Actionクラスのアノテーションは誰かが解析してexecuteConfigに設定済み。どこでやってんだこれ。DIコンテナ方面か。

まとめ

ソースの流れ追って、デバッガでステップ実行したけどこれくらいしかわからなかった。
S2ExecuteConfig作ってるのはActionCustomizerらしい。このへんの流れはS2Containerの知識が必要。
DIコンテナがあると処理の流れが非常に追いにくくて困る。規約知ってればわかりやすいんでしょうけどね。

関連:S2AOPを読む - <s>gnarl,</s>技術メモ”’<marquee><textarea>¥