Hot questions for Using Enterprise JavaBeans in websphere

Question:

I have an application, that is deployed on multiple nodes on WebSphere 8.5.5.2 The app contains some business logic that should be executed exactly once (if it was executed on one node, it shouldn't be executed on other nodes).

How can I achieve this? The only solution I invented, is to create a separate ear with this specific logic and create a separate node for it. Is there any other way?


Answer:

You could configure all nodes to access the same database, then have the code create a row in the database, and if the row doesn't already exist, then perform the code exactly once; committing the create of the database row.

If you need to have the code run exactly once at some schedule/interval, then you could use a persistent EJB timer. If all servers in a cluster are configured to use the same database, then the EJB timer will run on schedule on exactly one of the server instances.

The following information about configuring the EJB Timer server for a cluster my be helpful : https://www.ibm.com/support/knowledgecenter/en/SSAW57_8.5.5/com.ibm.websphere.nd.doc/ae/rejb_timerservice_v8.html

Question:

I have a daily job that is using a remote EJB, most of the times it works fine, but once a week it throws the following exception and fails.

CORBA NO_IMPLEMENT 0x49421042 - No Cluster Data Available vmcid: 0x49421000 minor code: 42

After some research I found that this can be caused by the restart of the remote cell.

This error is often seen for a short time when first requests for a cluster are made after startup of a cell

The problem is that my scheduled job is requesting this remote EJB 10 times and all of them fail. The next time the job runs, it works fine.

HA Manager is enabled across all the JVMs, but the application that make the request is in a different core group.

How can I handle this problem? Can this exception be caused by something else?


Answer:

If you have separate core groups they need to be bridged. If they are not bridged, some parts of the cell don't have complete information which can result in "No Cluster Data Available". See #4 on the WLM troubleshooting FAQ: https://www.ibm.com/developerworks/community/blogs/aimsupport/entry/Troubleshooting_WLM_issues_in_WebSphere_Application_Server?lang=en

Question:

I've just found some EJB behaviour which looks rather surprizing to me.

Here is the code sample (for sure MyBean, beanA, beanB are EJBs using CMT):

@Stateless
public class MyBean {
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void myMethod(){
         try {
             beanA.methodA(); /* annotated as REQUIRED */
         } catch (Exception e) {
             beanB.methodB(); /* annotated as NOT_SUPPORTED */
         }
    }
}

Lets's say methodA takes more than transaction timeout to execute, so once it returns myMethod receives TransactionRolledbackException, which is successfully caught then in "myMethod".

I would expect "methodB" be called so far, as accordingly with EJB spec it must be called without any transaction context. But actually, the "beanB" proxy simply returns another TransactionRolledbackException, the "methodB" is not executed.

Looking through EJB spec I do not see anything to prove that container should or even might behave that way.

Do I miss something? Any hint would be appreciated.

UPDATE

At least for Websphere, this behaviour appears to be timeout-specific. The "rollbackOnly" flag which for example is set when "methodA" throws a RuntimeException, does not prevent "methodB" from execution. Only timeout flag does.


Answer:

The EJB specification does not specifically address this scenario, other than to indicate that once a transaction has been marked for rollback, then "Continuing transaction is fruitless", and for the handling of NOT_SUPPORTED, the specification indicates it "does not prescribe how the container should manage the execution of a method with an unspecified transaction context".

All versions of WebSphere Application Server have taken the approach that the best way to handle the scenario where an EJB method has been marked for rollback only is to prevent all further actions the container has control over, so that the transaction may be rolled back as quickly as possible, ensuring the timely release of resources (such as database locks). Allowing a call to a NOT_SUPPORTED EJB method would result in the marked for rollback transaction being suspended; and thus continue to hold onto resources that could block or already be blocking other transactions. For this reason, WebSphere prevents such activity.

Question:

I am attempting to make a EJB call from Jboss (6.4 EAP) to WebSphere (7.x). I have a working example from WebSphere (WAS) to WAS, however, the same location and lookup name returns a name not found exception. I'm currently doing this testing inside of a web application deployed as a WAR into Jboss.

I do not have the EJB defined in a web.xml nor in a jboss-web.xml (I don't believe I need it). The EJB version in WebSphere is 2.1.

Properties env = new Properties();
env.put(Context.PROVIDER_URL, "corbaloc::example.test.com:11000");
InitialContext ctx = new InitialContext(env);
Object obj= ctx.lookup("cell/clusters/MyEJBHome12Cluster/MyEJBHome");

The above throws a NameNotFoundException:

javax.naming.NameNotFoundException: cell/clusters/MyEJBHome12Cluster/MyEJBHome -- service jboss.naming.context.java.cell.clusters."MyEJBHome12Cluster"."MyEJBHome"
    at org.jboss.as.naming.ServiceBasedNamingStore.lookup(ServiceBasedNamingStore.java:104)
    at org.jboss.as.naming.NamingContext.lookup(NamingContext.java:197)
    at org.jboss.as.naming.InitialContext$DefaultInitialContext.lookup(InitialContext.java:243)
    at org.jboss.as.naming.NamingContext.lookup(NamingContext.java:183)
    at org.jboss.as.naming.NamingContext.lookup(NamingContext.java:179)
    at javax.naming.InitialContext.lookup(InitialContext.java:411)
    at javax.naming.InitialContext.lookup(InitialContext.java:411)
    at com.test.ejbClient.getRemoteConnection(ejbClient.java:192)
    at com.test.ejbClient.runIt(ejbClient.java:77)
    at com.test.TestRemoteEJB.doGet(TestRemoteEJB.java:59)

I also attempted to use the sun factory: com.sun.jndi.cosnaming.CNCtxFactory

env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.cosnaming.CNCtxFactory");

That yields somewhat similar results:

javax.naming.NameNotFoundException [Root exception is org.omg.CosNaming.NamingContextPackage.NotFound: IDL:omg.org/CosNaming/NamingContext/NotFound:1.0]
    at com.sun.jndi.cosnaming.ExceptionMapper.mapException(ExceptionMapper.java:61)
    at com.sun.jndi.cosnaming.CNCtx.callResolve(CNCtx.java:502)
    at com.sun.jndi.cosnaming.CNCtx.lookup(CNCtx.java:541)
    at com.sun.jndi.cosnaming.CNCtx.lookup(CNCtx.java:519)
    at javax.naming.InitialContext.lookup(InitialContext.java:411)
    at javax.naming.InitialContext.lookup(InitialContext.java:411)
    at com.test.ejbClient.getRemoteConnection(ejbClient.java:192)
    at com.test.ejbClient.runIt(ejbClient.java:77)
    at com.test.TestRemoteEJB.doGet(TestRemoteEJB.java:59)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:734)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:295)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:231)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:149)
    at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:169)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:150)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:97)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:102)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:854)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:653)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:926)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.omg.CosNaming.NamingContextPackage.NotFound: IDL:omg.org/CosNaming/NamingContext/NotFound:1.0
    at org.omg.CosNaming.NamingContextPackage.NotFoundHelper.read(NotFoundHelper.java:72)
    at org.omg.CosNaming._NamingContextStub.resolve(_NamingContextStub.java:251)
    at com.sun.jndi.cosnaming.CNCtx.callResolve(CNCtx.java:488)

The above was attempted using the following site:Reference Link First

I then tried using the IBM client jars, just to see if I can get a call to work. I followed this site: Reference Link 2

I added 2 jars:

  • com.ibm.ws.ejb.thinclient_8.5.0.jar
  • com.ibm.ws.orb_8.5.0.jar

I also added all of the jars that contained the EJB classes and stub classes. I used the factory of com.ibm.websphere.naming.WsnInitialContextFactory. It looks up the EJB fine, but during the PortableRemoteObject.narrow call, it fails with a

java.lang.ClassCastException: com.test._MyEJBHome_Stub cannot be cast to org.omg.CORBA.Object

I doubt I would be able to use the WAS jars anyway as I have to run with Java 1.8, which won't work with the client jars I have above, nor do I prefer to use IBM jars inside of JBoss when Jboss should be able to do this.


Answer:

We did end up finding a solution to this issue. There is a magical set of characters that need to be in the lookup for JBoss. Previously, the provider URL and JNDI were separate. Now, they are all in the lookup String as shown below. Additionally, no other parameters were added to the InitialContext.

InitialContext ctx = new InitialContext(); // no need to add anything to the context

// A few reminders about the below:
// 1. For multiple hosts, separate with commas, i.e. "corbaname::@<server:port>,:@<server2:port2>"
// 2. If periods are used in the lookup name, they must be escaped, i.e. MyEJBHome-1.0 needs to be MyEJBHome-1\.0
Object obj= ctx.lookup("corbaname::@example.test.com:11000/NameServiceServerRoot#cell/clusters/MyEJBHome12Cluster/MyEJBHome");

// Normal EJB things below
MyEJBHome home = (MyEJBHome) javax.rmi.PortableRemoteObject.narrow(obj, MyEJBHome.class);
MyEJB myEJB = home.create();