|
| Problem | When creating EJB™s in a transaction that you have already marked for rollback, you get the following unexpected exception in WebSphere® Application Server V3.5 (all releases):
java.rmi.ServerException: RemoteException occurred in server thread;
nested exception is:
com.ibm.websphere.csi.CSITransactionRolledbackException:
Transaction timed out
| | Cause | Unlike V4.0 and V5.0, the method setRollbackOnly() rolls back the transaction immediately in all releases of V3.5. The transaction ends immediately instead of being deferred until the completion of the method that started the transaction, which is what happens in V4.0 and V5.0. Consequently, in V3.5, the method getRollbackOnly issues IllegalStateException, because there is no transaction. | | Solution | ScenarioYou enter a stateless session bean (with TX_REQUIRED) and do some business logic. You find out that you are unable to perform the desired task so you set the transaction to rollback by calling getSessionContext().setRollbackOnly() in the bean method. Before you return from the bean method you would like to log this error in the database by using another session bean with transaction attribute TX_REQUIRES_NEW. You want to rollback the business logic but commit the error log. However, when creating the home interface, you get this exception: java.rmi.ServerException: RemoteException occurred in server thread;
nested exception is:
com.ibm.websphere.csi.CSITransactionRolledbackException:
Transaction timed out Tested environmentsPlatforms that were tested and found to contain the problem: - VisualAge for Java™ 3.5.3 on Windows 2000
- WebSphere Application Server V3.5.4 on Windows® NT 4 SP6
- WebSphere Application Server V3.5.4 on AIX 4.3.3
Platforms that were tested and found to work correctly:- WebSphere Application Developer 4 (EJB 1.1)
- WebSphere Application Server V4
- WebSphere Application Developer 5 (EJB 2.0)
Simple test caseThis is a simple test case to show the problem. It uses two session beans as in the scenario above. The first stateless session bean with transaction attribute TX_REQUIRED (DoLogicBean) does setRollbackOnly() and then tries to create a second stateless session
bean (DoLogBean) that has got transaction attribute TX_REQUIRES_NEW.
This is all the code (most of it is debug information): public void doIt() throws Exception
System.out.println("DoLogic.doIt(): Enter");
System.out.println("DoLogic.doIt(): ------ getRollbackOnly = " +
getSessionContext().getRollbackOnly());
try
System.out.println("DoLogic.doIt(): Getting intial context
...");
javax.naming.InitialContext vContext = new InitialContext();
System.out.println("DoLogic.doIt(): setting rollback only ...");
getSessionContext().setRollbackOnly();
System.out.println("DoLogic.doIt(): ------ getRollbackOnly = " +
getSessionContext().getRollbackOnly());
System.out.println("DoLogic.doIt(): lookup bean named
anna/logic/DoLog...");
DoLogHome vDoLogHome =
(DoLogHome) javax.rmi.PortableRemoteObject.narrow(
vContext.lookup("anna/logic/DoLog"),
DoLogHome.class);
System.out.println("DoLogic.doIt(): create bean...");
DoLog vDoLog = vDoLogHome.create();
System.out.println("DoLogic.doIt(): call bean method (with
REQUIRES_NEW)...");
vDoLog.log();
System.out.println("DoLogic.doIt(): call bean method done, we
have made it|");
System.out.println("DoLogic.doIt(): ------ getRollbackOnly = " +
getSessionContext().getRollbackOnly());
catch (Exception e)
System.out.println("DoLogic.doIt(): Execption: " +
e.getMessage());
System.out.println("");
e.printStackTrace();
throw e;
System.out.println("DoLogic.doIt(): Exit");
Attached to this document are the JAR files with the two stateless session beans, and a simple Java client that calls them. Deploy the beans and then run the program DoIt. Description | JAR file | Exported deployed JAR from VAJ with session beans DoLogic (TX_REQUIRED)
and DoLog (TX_REQUIRES-NEW) | annatransejb13.jar | Exported Java and class files for the same two beans without deployed
code | annatransejb14nodepl.jar | Java code and class file for simple Java application DoIt for testing
the beans | annatranstester11.jar |
The output from the test case looks like this when it is run on V3.5.4: DoLogic.doIt(): Enter
DoLogic.doIt(): ------ getRollbackOnly = false
DoLogic.doIt(): Getting intial context ...
DoLogic.doIt(): setting rollback only ...
DoLogic.doIt(): ------ getRollbackOnly = true
DoLogic.doIt(): lookup bean named anna/logic/DoLog...
DoLogic.doIt(): create bean...
DoLogic.doIt(): Execption: RemoteException occurred in server thread;
nested exception is:
com.ibm.websphere.csi.CSITransactionRolledbackException: Transaction
timed out Updated to V3.5.6 and found other problems When running the same test cases on V3.5.6 on Windows NT, a different problem occurs. The container issues an IllegalStateException on the client side.com.ibm.ejs.container.UncheckedException: ; nested exception is: java.lang.IllegalStateException
There are some transaction differences between V3.5 and later releases causing the difference in behavior. The EJB implementation in V3.5 is different than the implementation in V4.0 and V5.0 releases, which are fully compliant to EJB 1.1 and EJB 2.0 specifications respectively. V3.5 was designed and released prior to the final EJB draft specifications, and addressed many aspects of the early EJB specification level, but is not fully compliant.
In some cases like these, an enhanced design is required to implement the required functionality. Following is an explanation of what occurs in V3.5 and a workaround that enables your application code to work unmodified from V3.5 through V5.0.
Unlike V4.0 and V5.0, the method setRollbackOnly() rollbacks the transaction immediately in V3.5. Therefore, the transaction ends immediately instead of being deferred until the completion of the method that started the transaction, as is done in V4.0 and V5.0. Consequently, in V3.5 the method getRollbackOnly() issues IllegalStateException, because there is no transaction.
This is the correct way to handle this as documented in the EJB 1.1 specification, 6.8.2 under the restrictions section. This function is consistent with the specification when the transaction is rolled back immediately as done in V3.5
To enhance V3.5 to rollback the transaction at the completion of the method starting the transaction is difficult due to the basic design. Therefore, the getRollbackOnly() returns false if the transaction has not been rolled back. Or it returns the IllegalStateException exception, which means the transaction did not exist or has been rolled back previous to the getRollbackOnly() call. It does not return true in V3.5.
Instead of not being able to address this as in V4.0 and V5.0, and considering this is the result of the base design of V3.5, we suggest a workaround that works in a straight forward manner and that is compatible with new versions of WebSphere Application Server.
Our suggestion is to modify the code to catch the exception and continue, such as: boolean rollbackonlyStatus=false; try{ rollbackonlyStatus=sessionContext.getRollbackOnly();// for 4.0 or 5.0 this will not throw exception. }catch(IllegalStateException e){ //Catch InvalidStateException for 3.5 rollbackonlyStatus=true; } if(rollbackonlyStatus==true){ // continue with // logging bean and abort.... }
This provides a solution for minimal effort, and ensures that the application code works across releases. | |
| | |
| |
|
Product categories: Software, Application Servers, Distributed Application & Web Servers, WebSphere Application Server, EJB Container Operating system(s): Multi-Platform Software version: 3.5 Software edition: Advanced Reference #: 1105546 IBM Group: Software Group Modified date: 2004-12-09
(C) Copyright IBM Corporation 2000, 2004. All Rights Reserved.
|