GlassFish上でStrutsにEJBをDI
これは単なる実験で、本気で使おうとかいう話ではないです。
GlassFishのJSF実装のソースを眺めていたところ、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|#]
・・・動いた(笑)
このインターフェイス、GlassFishのJSF専用なのは勿体ないですね。公開すればもっとJavaEEサーバの可能性も広がるだろうに