私の仕事は、サーブレットを使用してある種の Web サービス アダプターを作成し、それがアダプター EJB (SOAP Web サービス) を呼び出し、それが既存のサービス メソッド (EJB も) を呼び出すことです。既存のアーキテクチャは EJB 2.0 に基づいており、今のところ変更できません。外部の顧客は、Web サービス クラスではなく、サーブレットに直接アクセスすることになっています。これは、HTTPRequest 内の情報を使用して前処理を行う必要があるためです (証明書と HTTP ヘッダーからのユーザー ID の取得とマッピング)。そのため、サーブレットは doPost() メソッドに反応し、SOAP XML データの解析やマーシャリングなどの前処理を実行してから、アダプター EJB (ステートレス セッション Bean)、より正確には Web サービス メソッドを呼び出します。 EJB。これは、EJB が既存のセッション resp を必要とするまではうまく機能します。トランザクションのロールバックが処理される次の場合のように、SessionContext:
protected void preventTransactionRolledBackException() {
if (this.getSessionContext().getRollbackOnly()) {
this.getSessionContext().setRollbackOnly();
}
}
私のセットアップでは、SessionContext は常に null です。アプリケーション全体がすでに非常に複雑であるため、関連するものを除外しないことを願って、サーブレットと 1 つの EJB のみを使用して単純化したセットアップを投稿しようとしました。システム: WebSphere Application Server 8.5
サーブレット:
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() サービスでは適切な結果が得られますが、セッション関連のものが必要になるとすぐに失敗します。
もちろん、私はいくつかの調査を行いましたが、特に興味深いのは次のリンクでした: JBOSS で SessionContext を取得する方法。 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 が自動的に作成される必要があることを理解しました。しかし、そうでない場合、新しいオプションを作成する必要があるオプションはどれですか? さらなる質問: サーブレットは、私がアクセスできるセッション (request.getSession() ) も「作成」しますが、これは別のものです (HTTPSession)。このセッション オブジェクトをセッション Bean に共有または「変換」することはできないのでしょうか?