Localeによるリソース選択Interceptorの問題解消

何度かModelDrivenにしないと意図通りに動作しないとか、ModelになくActionに有るプロパティがsetされないと書いていたが、原因が判明した。
悪さをしていたのは Localeによるdispatch先の選択2 - Struts 2+Spring 2+Tiles+Acegi+iBatis+GWT+JUnit 4+JMockit でフルスタックJAVAフレームワークだった。

ValueStackで参照できるように次のようなコードで実装していたが、同じように新たなオブジェクトを積むExceptionMappingInterceptorのコードを参照するとsetではなくpushでオブジェクトを積んでいた。

その実装に習って、このコードを

   stack.set( "localed", this );

次のように変更した

   stack.push( this );

そして、localedはプロパティとして参照できるように、getLocaledを用意してあげる。
これで、ModelDrivenでModel側にプロパティが見つからなければ、正しくAction側(スタックの下側)のプロパティが呼ばれるようになった。

全体はつぎのようになる。

jp.co.hershe.struts2.util.LocaleResourceInterceptor.java

package jp.co.hershe.struts2.util;

import java.net.URL;
import java.text.MessageFormat;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.util.ValueStack;


/**
 * 国際化対応アプリケーション用のインターセプタ
 * 
 * 結果を Locale 設定に従いそれぞれ固有のページで表示をする場合に
 * 利用する。
 * 
 *  <result>$( localed.resource( "{0}/edit.jsp" )</result>
 *  とすると Locale の Language が ja の場合 /ja/edit.jsp を探し
 *  あればそちら、無ければ /edit.jsp を表示する。
 * @author mikuni
 *
 */
public class LocaleResourceInterceptor extends AbstractInterceptor {

    public void destroy() {
    }

    public void init() {
    }

    // スタックに localed として自分を登録
    public String intercept(ActionInvocation invocation) throws Exception {
        final ValueStack stack =  invocation.getStack();
        stack.push( this );
        return invocation.invoke();
    }

    public LocaleResourceInterceptor getLocaled() {
        return this;
    }

    // 置き換え処理を行う
    public String resource( String url ) throws Exception {
        Locale loc = ActionContext.getContext().getLocale();
        String ans = MessageFormat.format(url, new Object[]{ "/"+loc.getLanguage(), "/"+loc.getCountry() } ); 
        HttpServletRequest request = ServletActionContext.getRequest();
        URL u = ServletActionContext.getServletContext().getResource(ans);
        if (u!=null) {
        	return ans;
        }
        ans = MessageFormat.format(url, new Object[]{ "", "" } );
        return ans;
    }
}

struts.xml への記述に変更は必要無く、今まで通りである。

<result-types>
    <result-type name="templ" class="jp.co.hershe.struts2.util.TemplateResult"  default="true">
       <param name="template">${ localed.resource( "{0}#file#" ) }</param>
       <param name="key">#file#</param>
    </result-type>
</result-types>