-Tapestry-S2連携再考(2)
再考結果、やれそうな気がしてます。まず、Globalの汚染を回避するべく、前回レベルの実装をやりなおしてみました。
まず、Globalオブジェクトはユーザーが何か設定するかもしれないので、ラップします。本当は、バイトコードエンジニアリングで、getS2Container()もったインターフェイスをユーザー設定されたGlobalクラスにダイナミックにimplementsしたほうがユーザーのキャストで切り分けられるので良いのでしょうが、主題はこっちじゃないので軽くファサードでやりました。
package org.seasar.contribute.tapestry; import org.seasar.framework.container.S2Container; public class GlobalProxy { private Object global; private S2Container container; public GlobalProxy(Object global, S2Container container) { this.global = global; this.container = container; } public Object getGlobal() { return global; } public S2Container getS2Container() { return container; } }
次に、このラップしたGlobalProxyクラスに対応したOGNLプロパティアクセッサ。あらかじめ用意されているObjectPropertyAccessorを継承して、ユーザー独自のGlobalオブジェクトにも対応。
package org.seasar.contribute.tapestry; import java.util.Map; import org.seasar.framework.container.S2Container; import ognl.ObjectPropertyAccessor; import ognl.OgnlException; public class GlobalProxyPropertyAccessor extends ObjectPropertyAccessor { public Object getProperty(Map cx, Object target, Object name) throws OgnlException { // S2用のコンポーネント取得メソッドOGNL版 GlobalProxy proxy = (GlobalProxy)target; S2Container container = proxy.getS2Container(); String componentName = name.toString(); if(container.hasComponentDef(componentName)) { // S2Containerからコンポーネント取得 return container.getComponent(componentName); } else { // ユーザーGlobalからプロパティ取得 return super.getProperty(cx, proxy.getGlobal(), name); } } }
そして、エンジンのカスタマイズです。やり方けっこう変えてます。
package org.seasar.contribute.tapestry; import ognl.OgnlRuntime; import org.apache.tapestry.IRequestCycle; import org.apache.tapestry.engine.BaseEngine; import org.apache.tapestry.engine.IEngineService; import org.apache.tapestry.engine.IMonitor; import org.apache.tapestry.request.RequestContext; import org.seasar.framework.container.S2Container; import org.seasar.framework.container.factory.S2ContainerFactory; public class WithS2Engine extends BaseEngine { public static final String CONFIG_PATH = "seasar_config"; static { OgnlRuntime.setPropertyAccessor( GlobalProxy.class, new GlobalProxyPropertyAccessor()); } protected Object createGlobal(RequestContext context) { S2Container container = null; String path = getSpecification().getProperty(CONFIG_PATH); if(path != null) { container = S2ContainerFactory.create(path); } Object global = super.createGlobal(context); if(container == null) { return global; } else { // S2Containerをproxyで包む。 return new GlobalProxy(global, container); } } // protected IRequestCycle createRequestCycle( // RequestContext context, IEngineService service, IMonitor monitor) { // // こいつはまだきちんと動かない // return new RequestCycleProxy(this, context, service, monitor); // } }
あとは、ページからOGNLでコンポーネントを取得するときには、"global.counter.count"です。