-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"です。