java - 从 Servlet 调用的 Session-Bean 中,SessionContext 始终为 null

标签 java servlets jakarta-ee ejb sessioncontext

我的工作是使用 Servlet 编写一种 Web 服务适配器,然后调用适配器 EJB(SOAP Web 服务),而适配器 EJB 又调用现有的服务方法(也是 EJB)。 现有的架构基于EJB 2.0,我暂时无法更改。 外部客户应该直接访问 Servlet 而不是 Webservice 类。 原因是需要使用 HTTPRequest 中的信息进行一些预处理(从证书和 HTTP header 中获取和映射用户 ID)。 因此,Servlet 对 doPost() 方法使用react,执行解析和编码 SOAP XML 数据等预处理,然后调用适配器 EJB(无状态 session Bean), 更准确地说,Web 服务方法将触发不同 EJB 中的现有服务方法。 到目前为止,这种方法运行良好,直到 EJB 需要现有的 session 或 session 为止。 SessionContext,就像下面处理事务回滚的情况:

protected void preventTransactionRolledBackException() {
    if (this.getSessionContext().getRollbackOnly()) {
        this.getSessionContext().setRollbackOnly();
    }
}

在我的设置中,SessionContext 始终为空。 由于整个应用程序已经相当复杂,我尝试仅使用 Servlet 和一个 EJB 发布一个简化的设置,希望我不会排除相关的内容。 系统:WebSphere应用服务器8.5

Servlet:

public class NewZekEclsServiceServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String operation = null;
        response.setContentType("text/xml");
        try { 
            PrintWriter out = response.getWriter(); 
            // Get Header data
            // Get Attribute data
            // Get Body data:
            InputStream body = request.getInputStream();
            String xml = IOUtils.toString(body, "UTF-8");

            DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
            docBuilderFactory.setNamespaceAware(true); // required as several namespaces might be used
            DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
            Document doc = docBuilder.parse(new InputSource(new StringReader(xml)));

            operation = getOperation(doc); // method which scans the xml to retrieve the correct operation to use.

            if (operation.equalsIgnoreCase("Ping")) {

                // Calling the Adapter Bean:
                EclsTestBeanBean eclsTestBean = new EclsTestBeanBean();
                eclsTestBean.ejbCreate();

                PingIn pingIn = new PingIn();
                PingOut pingOut = eclsTestBean.ping(pingIn);

                String xmlString = convertEclsObjectToSOAPString(pingOut);
                out.print(xmlString);

            }
        }
    }
}

EJB(由 Rational Application Developer 9.0 生成):

/**
 * Bean implementation class for Session Bean: EclsTestBean
 *
 * @ejb.bean
 *  name="EclsTestBean"
 *  type="Stateless"
 *  jndi-name="ejb/ch/zek/ecls/EclsTestBeanHome"
 *  view-type="remote"
 *  transaction-type="Bean"
 *
 * @ejb.home
 *  remote-class="ch.zek.ecls.EclsTestBeanHome"
 *
 * @ejb.interface
 *  remote-class="ch.zek.ecls.EclsTestBean"
 *
 */
public class EclsTestBeanBean implements javax.ejb.SessionBean {

    private Log log = LogFactory.getLog(EcodeAbfragenAction.class);

    private SessionContext mySessionCtx;

    public SessionContext getSessionContext() {
        return mySessionCtx;
    }

    public void setSessionContext(SessionContext ctx) {
        mySessionCtx = ctx;
    }

    public void ejbCreate() throws CreateException {}
    public void ejbActivate() {}
    public void ejbPassivate() {}
    public void ejbRemove() {}

    /**
     * Basic ping service for ECLS
     * @param parameters
     * @return
     * @throws PingEntityNotFoundException
     * @throws PingPermissionException
     * @throws PingSystemException
     */
    public ch.zek.ecls.PingOut ping(ch.zek.ecls.PingIn parameters) throws java.rmi.RemoteException, ch.zek.ecls.PingPermissionException, ch.zek.ecls.PingEntityNotFoundException, ch.zek.ecls.PingSystemException {

        PingOut pingOut = new PingOut();
        String pingAnswer = "Ping_ECLS_v1";
        String adapter = "";
        String operation = "";

        Parameter[] msgParams = new Parameter[1];
        String eclsEnvironment = "TEST";
        pingAnswer += "_" + eclsEnvironment;

        logAvailableEjbs();

        try {
            if (mySessionCtx != null) { // Why can it be null at all?
                log.debug("mySessionCtx: " + mySessionCtx.getContextData());
            } else {
                log.debug("mySessionCtx was null");
                InitialContext ic = new InitialContext();
                mySessionCtx = (SessionContext) ic.lookup("java:comp/env/sessionContext"); // gives error:  javax.naming.NameNotFoundException: Name "comp/env/sessionContext" not found in context "java:".
                System.out.println("mySessionCtx: " + mySessionCtx);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // creating the SOAP data... not relevant for the problem.
        msgParams[0] = new Parameter();
        msgParams[0].setValue(pingAnswer);
        SystemMessage systemMessage = new SystemMessage();
        systemMessage.setCode("OK");
        systemMessage.setMessage("Ping");
        systemMessage.setParameter(msgParams);
        pingOut.setSystemMessage(systemMessage);

        return pingOut;
    }

    /**
     * ONLY USED DURING DEVELOPMENT:
     * Helper method to print "accessible" EJBs.
     */
    protected void logAvailableEjbs() {
        try {
            //Get the Initial Context for the JNDI lookup for a local EJB
            InitialContext ic = new InitialContext();

            NamingEnumeration<NameClassPair> list;
            String level = "";
            String name = "";
            list = ic.list(level);
            while (list.hasMore()) {
                name = list.next().getName();
                System.out.println(level + "/" + name);
            }
            level = "ejb";
            list = ic.list(level);
            while (list.hasMore()) {
                name = list.next().getName();
                System.out.println(level + "/" + name);
            }   
            level = "java:comp";
            list = ic.list(level);
            while (list.hasMore()) {
                name = list.next().getName();
                System.out.println(level + "/" + name);
            }
            level = "java:comp/env";
            list = ic.list(level);
            while (list.hasMore()) {
                name = list.next().getName();
                System.out.println(level + "/" + name);
            }
            /*
            level = "java:comp/env/ejb"; // Throws Error!
            list = ic.list(level);
            while (list.hasMore()) {
                name = list.next().getName();
                System.out.println(level + "/" + name);
            }
            */
            level = "java:global";
            list = ic.list(level);
            while (list.hasMore()) {
                name = list.next().getName();
                System.out.println(level + "/" + name);
            }
        } catch (NamingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

我们正在使用 SoapUI 工具 ( http://www.soapui.org ) 测试设置。同样,我们为简单的 Ping() 服务获得了正确的结果,但是一旦需要与 session 相关的内容,它就会失败。

当然我做了一些研究,特别有趣的是这个链接: How to get SessionContext in JBOSS 这也指: http://javahowto.blogspot.co.uk/2006/06/4-ways-to-get-ejbcontext-in-ejb-3.html

关于 EJB 生命周期:docs.oracle.com/cd/E13224_01/wlw/docs100/guide/ejb/session/conSessionBeanLifeCycle.html J2EE 教程:docs.oracle.com/javaee/6/tutorial/doc/gipss.html#gipsx (抱歉,不能发布超过 2 个链接...)

但正如代码中所述,我无法访问 java:comp/env/ejb/sessionContext。好吧...甚至 java:comp/env/ejb 也没有。 我编写了一个脏帮助器方法来查看 EJB 实际可以访问的内容并获得以下输出:

SystemOut     O /jta
SystemOut     O /eis
SystemOut     O /cell
SystemOut     O /thisNode
SystemOut     O /DefaultDatasource
SystemOut     O /services
SystemOut     O /jdbc
SystemOut     O /servername
SystemOut     O /com.ibm.websphere.ejbcontainer
SystemOut     O /com
SystemOut     O /zek
SystemOut     O /wm
SystemOut     O /ejb
SystemOut     O /Increment
SystemOut     O /tm
SystemOut     O ejb/ivtEJBObject
SystemOut     O ejb/ch
SystemOut     O ejb/mgmt
SystemOut     O java:comp/ValidatorFactory
SystemOut     O java:comp/TransactionSynchronizationRegistry
SystemOut     O java:comp/ORB
SystemOut     O java:comp/Validator
SystemOut     O java:comp/UserTransaction
SystemOut     O java:comp/env
SystemOut     O java:comp/BeanManager
SystemOut     O java:comp/websphere
SystemOut     O java:comp/HandleDelegate
SystemOut     O java:global/com.ibm.ws.AppNameSpaces
SystemOut     O java:global/NewZekEar
SystemOut     O java:global/SchedulerCalendars
SystemOut     O java:global/DefaultApplication
SystemOut     O java:global/cell
SystemOut     O java:global/query
SystemOut     O java:global/ManagementEJB
SystemOut     O java:global/ivtApp

我还尝试使用注释:

@Resource
private SessionContext mySessionCtx;

或者设置不同的交易类型:

transaction-type="Container"

没有任何帮助。 我理解 SessionContext 应该自动创建。但如果不是——必须选择哪种选项来创建新的选项? 进一步问题: servlet 还“创建”了一个我可以访问的 session (request.getSession()),但这是不同的(HTTPSession)。我想我无法将此 session 对象共享或“转换”为 session Bean?

最佳答案

您自己实例化了 EclsTestBeanBean:

EclsTestBeanBean eclsTestBean = new EclsTestBeanBean();

EJB 依赖于将对象包装在代理中,以允许容器添加额外的服务,包括依赖注入(inject) session 上下文,这意味着只有容器可以创建它们并发出它们。您还会发现该对象不会执行任何 EJB 服务,它只是一个 POJO。

要从容器请求 EJB,您需要通过依赖项注入(inject)请求它或从 JNDI 查找它,按照以下答案:

JPA entity manager not correctly injected - Weblogic

那么下一个问题是您的 bean 似乎在 JNDI 中不可用 - 我认为这是因为您没有为其定义本地或远程接口(interface)。这在使用“无接口(interface)” View 的 EJB3 中很好,但在 EJB2 中则不然: http://help.eclipse.org/luna/index.jsp?topic=%2Forg.eclipse.jst.ejb.doc.user%2Ftopics%2Fcearch.html

所以我建议 - 自己编写一个接口(interface)(希望如此),然后 EclsTestBeanBean 在 JNDI 中可用,并从那里查找它而不是实例化它。

(使用 @Resource 注释,请注意,所有基于注释的工作也已添加到 EJB3 中。)

关于java - 从 Servlet 调用的 Session-Bean 中,SessionContext 始终为 null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34676918/

相关文章:

java - 如何在不使用 FlexContext 的情况下从 Java 服务对象访问主体?

java - 在 Android Studio 中导入 Google Play Services 库

java - 在方法中获取 SharedPreferences 的上下文

java - request.getRemoteUser() 有时会返回 null

java web 应用程序架构,很多 war 在耳朵里,或者一场 war 有很多 jar

java - 当我什至没有部署 Web 应用程序时,为什么会看到 HttpResponseCode '200'?

java - 如何检查书签是否包含表格?

java - 字符串值 = 4.30000000e+01 如何解析Int?

java - 如何使用 getParameterNames() 值

org.apache.naming.resources.DirContextURLConnection.getInputStream 处的 java.io.FileNotFoundException