Bean Managed Stateless session Bean's Transaction Problems
robinpaul Dec 14, 2001 8:03 AMhi all,
We were using BEA Weblogic 5.1 and quite recently we decided to test our fully developed/tested Application on JBoss. Beleive me , we are having a nightmare . .
I dont know whether it is a configuration related problem or something else
my server's jcml files contents are shown below
<!-- ==================================================================== -->
<!-- Transactions -->
<!-- ==================================================================== -->
300
oracle.jdbc.xa.OracleXid
<!-- ==================================================================== -->
<!-- JDBC -->
<!-- ==================================================================== -->
oracle.jdbc.driver.OracleDriver
DefaultDS
org.jboss.pool.jdbc.xa.wrapper.XADataSourceImpl
jdbc:oracle:thin:@10.21.2.7:1521:sun8
60000
xxx
10
xxx
true
false
false
true
60000
60000
true
true
1.0
0
I'll list down some of the observations regarding (BMT)Stateless Session Bean's Transaction Management
case 1) (and the most deadly)
In your business method of your bean do the following in the specified sequence
a get a database connection
b get a User Transaction Object from the Session Context
c begin your transaction
d do some inserts, updates, deletes
e commit your transaction
f close your connection
Result) As observed on JBoss Server version 2.4.1 and 2.4.3
The server doesnt commit and does not throw any exception
case 2) (work around for case 1)
If we do the following every thing works fine
a. get a User Transaction Object from the Session Context
c begin your transaction
b. get a database connection
d. do some inserts, updates, deletes
e commit your transaction
f close your connection
Result) As observed on JBoss Server version 2.4.1 and 2.4.3
The server commit and works as it should
case 3) a. get a User Transaction Object from the Session Context
b begin your transaction
c. get a database connection
d do some inserts, updates, deletes
e. close your connection
f. commit your transaction
Result) As observed on JBoss Server version 2.4.1 and 2.4.3
The server throws Incomplete Transaction Exception
Stack trace on the client
Inside Main
ServerRef: Got the Context
ServerRef:Looking for ejb.BMTTest
Got Remote
Firing method - - -
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.RemoteException: Application error: BMT stateless bean BMTTestBean should complete transactions before returning (ejb1.1 spec, 11.6.1)
java.rmi.RemoteException: Application error: BMT stateless bean BMTTestBean should complete transactions before returning (ejb1.1 spec, 11.6.1)
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:248)
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:223)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:128)
at org.jboss.ejb.plugins.jrmp.server.JRMPContainerInvoker_Stub.invoke(Unknown Source)
at org.jboss.ejb.plugins.jrmp.interfaces.GenericProxy.invokeContainer(GenericProxy.java:357)
at org.jboss.ejb.plugins.jrmp.interfaces.StatelessSessionProxy.invoke(StatelessSessionProxy.java:123)
at $Proxy1.transactionTestMethod(Unknown Source)
at BMTTestClient.main(BMTTestClient.java:40)
Exception in thread "main" Interactive Session Ended
Stack trace on the Server
[MailService] Started
[Service Control] Started 35 services
[Default] JBoss 2.4.3 Started in 0m:52s
[DefaultDS] No transaction right now.
[DefaultDS] Pool DefaultDS [1/1/10] gave out pooled object: org.jboss.pool.jdbc.xa.wrapper.XAConnectionImpl@60a386
[DefaultDS] java.lang.IllegalArgumentException: null xaRes
[Default] java.lang.RuntimeException: Unable to deregister with TransactionManager: java.lang.IllegalArgumentException: null xaRes
[Default] at org.jboss.pool.jdbc.xa.XAConnectionFactory$2.closeConnection(XAConnectionFactory.java:110)
[Default]
[Default] at org.jboss.pool.jdbc.xa.XAConnectionFactory$2.connectionClosed(XAConnectionFactory.java:89)
[Default]
[Default] at org.jboss.pool.jdbc.xa.wrapper.XAConnectionImpl.clientConnectionClosed(XAConnectionImpl.java:134)
[Default]
[Default] at org.jboss.pool.jdbc.xa.wrapper.XAClientConnection.close(XAClientConnection.java:250)
[Default]
[Default] at BMTTestBean.transactionTestMethod(BMTTestBean.java:79)
[Default]
[Default] at java.lang.reflect.Method.invoke(Native Method)
[Default]
[Default] at org.jboss.ejb.StatelessSessionContainer$ContainerInterceptor.invoke(StatelessSessionContainer.java:543)
[Default]
[Default] at org.jboss.ejb.plugins.TxInterceptorBMT.invoke(TxInterceptorBMT.java:276)
[Default]
[Default] at org.jboss.ejb.plugins.StatelessSessionInstanceInterceptor.invoke(StatelessSessionInstanceInterceptor.java:87)
[Default]
[Default] at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:128)
[Default]
[Default] at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:195)
[Default]
[Default] at org.jboss.ejb.StatelessSessionContainer.invoke(StatelessSessionContainer.java:286)
[Default]
[Default] at org.jboss.ejb.plugins.jrmp.server.JRMPContainerInvoker.invoke(JRMPContainerInvoker.java:395)
[Default]
[Default] at java.lang.reflect.Method.invoke(Native Method)
[Default]
[Default] at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:241)
[Default]
[Default] at sun.rmi.transport.Transport$1.run(Transport.java:142)
[Default]
[Default] at java.security.AccessController.doPrivileged(Native Method)
[Default]
[Default] at sun.rmi.transport.Transport.serviceCall(Transport.java:139)
[Default]
[Default] at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:443)
[Default]
[Default] at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:643)
[Default]
[Default] at java.lang.Thread.run(Thread.java:484)
[Default]
[BMTTestBean] Application error: BMT stateless bean BMTTestBean should complete transactions before returning (ejb1.1 spec, 11.6.1)
Please note that all these combinations works fine on Weblogic 5.1.0 Server. Can someone give us an explanation why it does not work for case 1 and case 3
The sample source code is as given below
Bean
import javax.ejb.*;
import javax.transaction.*;
import java.sql.*;
import javax.sql.*;
import javax.naming.*;
public class BMTTestBean implements SessionBean
{
private SessionContext sessionContext;
private UserTransaction ut;
private DataSource ds;
public void ejbCreate() throws CreateException
{
}
public void ejbRemove()
{
}
public void ejbActivate()
{
}
public void ejbPassivate()
{
}
public void setSessionContext(SessionContext context)
{
sessionContext = context;
}
public void transactionTestMethod()
{
Connection con = null;
PreparedStatement stmt = null;
StringBuffer sbf1 = new StringBuffer("Insert into test_table( id, name) values (1,'Robin Paul')");
StringBuffer sbf2 = new StringBuffer("Insert into test_table( id, name) values (2,'Jikky John')");
try
{
con = getConnection();
ut = sessionContext.getUserTransaction();
ut.begin();
stmt = con.prepareStatement(sbf1.toString());
sbf1 = null;
stmt.executeUpdate();
stmt.close();
stmt = con.prepareStatement(sbf2.toString());
sbf2 = null;
stmt.executeUpdate();
ut.commit();
}
catch( Exception se )
{
se.printStackTrace();
try
{
ut.rollback();
}
catch( Exception e)
{
e.printStackTrace();
}
}
finally
{
try
{
if( stmt != null )
{
stmt.close();
}
if( con != null )
{
con.close();
}
}
catch( SQLException se)
{
se.printStackTrace();
}
}
}
private Connection getConnection() throws Exception
{
InitialContext initCtx = null;
initCtx = new InitialContext();
ds = (javax.sql.DataSource) initCtx.lookup("java:comp/env/jdbc/oraclePool");
initCtx.close();
return ds.getConnection();
}
}
*************************** Home ******************
import javax.ejb.EJBHome;
import javax.ejb.CreateException;
import java.rmi.RemoteException;
public interface BMTTestHome extends EJBHome
{
public BMTTest create() throws CreateException, RemoteException;
}
******************** Remote *****************************
import javax.ejb.EJBObject;
import javax.ejb.CreateException;
import java.rmi.RemoteException;
public interface BMTTest extends EJBObject
{
public void transactionTestMethod() throws RemoteException;
}
*********************** ejb -jar.xml *****************************
<?xml version="1.0" encoding="Cp1252"?>
<!DOCTYPE ejb-jar PUBLIC '-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN' 'http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd'>
<ejb-jar>
<enterprise-beans>
<ejb-name>BMTTestBean</ejb-name>
BMTTestHome
BMTTest
<ejb-class>BMTTestBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Bean</transaction-type>
<resource-ref>
<res-ref-name>jdbc/oraclePool</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</enterprise-beans>
</ejb-jar>
******************************jboss.xml***************************
<?xml version="1.0" encoding="UTF-8"?>
<enterprise-beans>
<ejb-name>BMTTestBean</ejb-name>
<jndi-name>ejb.BMTTest</jndi-name>
<reference-descriptor>
<resource-description>
<res-ref-name>jdbc/oraclePool</res-ref-name>
<jndi-name>java:/DefaultDS</jndi-name>
</resource-description>
</reference-descriptor>
</enterprise-beans>
*********************Client.java*************************************
import java.util.*;
import javax.ejb.*;
import javax.naming.*;
import java.rmi.*;
import java.util.*;
import javax.rmi.PortableRemoteObject;
public class BMTTestClient
{
public static Object getServerRef(String JNDIName)
{
Object serverRef = null;
try
{
Properties h = new Properties();
h.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory" );
h.put(Context.PROVIDER_URL,"10.21.13.5:1099");
InitialContext ctx = new InitialContext(h);
System.out.println("ServerRef: Got the Context");
System.out.println("ServerRef:Looking for " + JNDIName);
serverRef = ctx.lookup(JNDIName);
}
catch(NamingException e)
{
e.printStackTrace();
}
return serverRef;
}
public static void main( String args[] ) throws Exception
{
System.out.println("Inside Main");
Object beanRef = getServerRef( "ejb.BMTTest" );
BMTTestHome beanHome = (BMTTestHome)PortableRemoteObject.narrow(beanRef, BMTTestHome.class);
BMTTest beanRemote = beanHome.create();
System.out.println("Got Remote");
System.out.println("Firing method - - - ");
beanRemote.transactionTestMethod();
System.out.println("success");
}
}
Thanks and Regards
Robin Paul