我的工作是使用Servlet编写一种Web服务适配器,然后调用适配器EJB(SOAP Web服务),后者又调用现有的服务方法(也称为EJB)。 现有的体系结构基于EJB 2.0,我现在无法改变。 外部客户应该直接访问Servlet而不是Web服务类。 这样做的原因是需要使用HTTPRequest中的信息(从证书和HTTP标头中获取和映射用户标识)来完成一些预处理。 因此,Servlet对doPost()方法做出反应,执行预处理,如解析和编组SOAP XML数据,然后调用适配器EJB(无状态会话Bean), 更准确地说,webservice方法将在不同的EJB中触发现有的服务方法。 到目前为止,这一点很有效,直到EJB需要现有的Session resp。 SessionContext,就像下面处理事务回滚的情况一样:
protected void preventTransactionRolledBackException() {
if (this.getSessionContext().getRollbackOnly()) {
this.getSessionContext().setRollbackOnly();
}
}
在我的设置中,SessionContext始终为null。 由于整个应用程序已经相当复杂,我尝试仅使用Servlet和一个EJB发布简化的设置,希望我不排除相关的东西。 系统:WebSphere Application Server 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()服务的正确结果,但只要需要与会话相关的东西,它就会失败。
当然我做了一些研究,特别有趣的是这个链接: 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还会创建&#34;我可以访问的会话(request.getSession()),但这是不同的(HTTPSession)。我想我无法分享或转换&#34;这个会话对象是会话Bean吗?
答案 0 :(得分:1)
您自己实例化EclsTestBeanBean
:
EclsTestBeanBean eclsTestBean = new EclsTestBeanBean();
EJB依赖于将对象包装在代理中以允许容器添加额外的服务,包括依赖注入会话上下文,这意味着只有容器可以创建它们并将它们分发出去。您还会发现此对象不会执行任何EJB服务,它只是一个POJO。
要从容器请求EJB,您需要通过依赖注入请求它或者从JNDI查找它,根据这个答案:
JPA entity manager not correctly injected - Weblogic
接下来的问题是你的bean似乎在JNDI中不可用 - 我想这是因为你还没有为它定义一个本地或远程接口。这在EJB3中很好,其中&#34; no-interface&#34;视图被使用,但不在EJB2中使用:http://help.eclipse.org/luna/index.jsp?topic=%2Forg.eclipse.jst.ejb.doc.user%2Ftopics%2Fcearch.html
所以我建议 - 给自己写一个接口,(希望)然后EclsTestBeanBean
然后在JNDI中可用,并从那里查找而不是实例化它。
(使用@Resource注释,请注意所有基于注释的工作也在EJB3中添加。)