GlassFish上でStrutsにEJBをDI

これは単なる実験で、本気で使おうとかいう話ではないです。
GlassFishJSF実装のソースを眺めていたところ、com.sun.faces.spi.InjectionProviderというインターフェイスが目に留まりました。どうやらこれを使ってJSFのManagedBeanにEJB等をDIしてるみたいです。メソッドを見ると、ManagedBeanはPOJOなので、単にオブジェクトとして引数に取っているだけでした。
・・・ということは、このクラスだけ使えば、JSF以外のFWでもEJBをDIできるのでは?・・・
ということで、GlassFish上でStrutsのWebプロジェクト(を含んだearプロジェクト)を作成し、RequestProcessorを適当に拡張してみました。
(2008/04/23追記 適当とはいえ、同期できていないソースは例としてどうかと思ったので若干修正)

package jsfsample.struts;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.tiles.TilesRequestProcessor;
import org.apache.struts.util.RequestUtils;

import com.sun.faces.spi.InjectionProvider;
import com.sun.faces.spi.InjectionProviderException;
import com.sun.faces.vendor.GlassFishInjectionProvider;

public class EJB3RequestProcessor extends TilesRequestProcessor {

	@Override
	protected Action processActionCreate(HttpServletRequest request,
			HttpServletResponse response, ActionMapping mapping)
			throws IOException {

		String className = mapping.getType();
		if (log.isDebugEnabled()) {
			log.debug(" Looking for Action instance for class " + className);
		}

		Action instance = null;

		if (log.isTraceEnabled()) {
			log.trace("  Creating new Action instance");
		}

		try {
			instance = (Action) RequestUtils.applicationInstance(className);
		} catch (Exception e) {
			log.error(getInternal().getMessage("actionCreate", mapping.getPath()), e);

			response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
				getInternal().getMessage("actionCreate", mapping.getPath()));

			return null;
		}

		instance.setServlet(this.servlet);
		InjectionProvider ip = new GlassFishInjectionProvider();
		try {
			ip.inject(instance);
			ip.invokePostConstruct(instance);
		} catch (InjectionProviderException e) {
			throw new RuntimeException(e);
		}


		return instance;
	}

	@Override
	protected ActionForward processActionPerform(HttpServletRequest request,
			HttpServletResponse response, Action action, ActionForm form,
			ActionMapping mapping) throws IOException, ServletException {

		ActionForward forward = super.processActionPerform(request, response,
				action, form, mapping);

		InjectionProvider ip = new GlassFishInjectionProvider();
		try {
			ip.invokePreDestroy(action);
		} catch (InjectionProviderException e) {
			throw new ServletException(e);
		}
		return forward;
	}

}

そしてActionを適当に実装

package jsfsample.action;

import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.EJB;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import jsfsample.bean.MapCategoryBean;
import jsfsample.entity.Map_categories;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

public class MapCategoryAction extends Action {
	
	@EJB
	private MapCategoryBean mcBean;
	
	@PostConstruct
	public void init() {
		System.out.println(this + ":start");
	}

	@Override
	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		
		List<Map_categories> list = mcBean.getMapCategories("コンビニ");
		request.setAttribute("list", list);
		return mapping.findForward("success");
	}
	
	@PreDestroy
	public void end() {
		System.out.println(this + ":end");
	}

}

手作りのRequestProcessorとActionをstruts-configに定義して実行

[#|2008-04-23T04:15:07.316+0900|INFO|sun-appserver9.1|javax.enterprise.system.stream.out|_ThreadID=17;_ThreadName=httpSSLWorkerThread-8080-0;|
jsfsample.action.MapCategoryAction@4477b0:start|#]

[#|2008-04-23T04:15:07.318+0900|FINE|sun-appserver9.1|oracle.toplink.essentials.session.file:/Users/hidenoshin/glassfish/domains/domain1/applications/j2ee-apps/jsfsample/jsfsampleEJB_jar/-mapsample.sql|_ThreadID=17;_ThreadName=httpSSLWorkerThread-8080-0;ClassName=null;MethodName=null;_RequestID=3245dfd2-aff5-4325-8709-9070d2bb2855;|SELECT ID, LOCK_VERSION, CREATED_AT, NAME, UPDATED_AT, ORDER_BY FROM MAP_CATEGORIES|#]

[#|2008-04-23T04:15:07.323+0900|INFO|sun-appserver9.1|javax.enterprise.system.stream.out|_ThreadID=17;_ThreadName=httpSSLWorkerThread-8080-0;|
jsfsample.action.MapCategoryAction@4477b0:end|#]

・・・動いた(笑)
このインターフェイスGlassFishJSF専用なのは勿体ないですね。公開すればもっとJavaEEサーバの可能性も広がるだろうに