0
votes

I have a requirement of trying to achieve transaction propagation across multiple stateful beans I have 3 Stateful EJB;s in my application.. The start and end transaction is controlled be an external java application through remote interface method invocation.

@Remote
@Stateful
public class MyEJB1 implements RemoteEJB1{
@EJB
 private RemoteEJB2 ejb2;
@Resource
UserTransaction utx;

public void startTransaction() {
    try {

        utx.begin();

    } catch (NotSupportedException e) {
        throw new EJBException(e);
    } catch (SystemException e) {
        throw new EJBException(e);
    }
}

public void commitTransaction() {
    try {
        utx.commit();

    } catch (SecurityException e) {
        throw new EJBException(e);
    } catch (IllegalStateException e) {
        throw new EJBException(e);
    } catch (RollbackException e) {
        throw new EJBException(e);
    } catch (HeuristicMixedException e) {
        throw new EJBException(e);
    } catch (HeuristicRollbackException e) {
        throw new EJBException(e);
    } catch (SystemException e) {
        throw new EJBException(e);
    }
}

public RemoteEJB2 getEJB2() {
    return ejb2;
}

}


public class MyEJB2 implements RemoteEJB2{

@EJB
private RemoteEJB3 ejb3;
@Resource(name = "java:jboss/datasources/MyDS")
private DataSource ds;

public RemoteEJB3 getEJB3() {
    return ejb3;
}

@TransactionAttribute(TransactionAttributeType.MANDATORY)
public void insertElement(String elementName) {
    PreparedStatement pStat = null;
    Connection con = null;
    try {
        con = ds.getConnection();
        String sql = "insert into TRANSACTIONTEST(COL1,COL2) values(?,?)";
        pStat = con.prepareStatement(sql);
        pStat.setString(1, elementName);
        pStat.setDouble(2, Math.random());
        pStat.executeUpdate();

    } catch (Exception ex) {
        ex.printStackTrace();
    } finally {
        try {
            con.close();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}
}

public class MyEJB3 implements RemoteEJB3{
@Resource(name="java:jboss/datasources/MyDS")
private DataSource ds;

@TransactionAttribute(TransactionAttributeType.MANDATORY)
public void updateElement(String newName) {
    PreparedStatement pStat = null;
    Connection con = null;
    try{    con = getDs().getConnection();
        String sql ="update  TRANSACTIONTEST set COL1=?";           
        pStat = con.prepareStatement(sql);
        pStat.setString(1, newName);        
        pStat.executeUpdate();

    }catch(Exception ex){
        ex.printStackTrace();
    }finally{
        try {
            con.close();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}
}

Test Class:

public class MyTest{
public static void main(String[] args) throws Exception {
    final Hashtable jndiProperties = new Hashtable();
    jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
    final Context context = new InitialContext(jndiProperties);
    MyEJB1 ejb1 = context.lookup("ejb:/EJBTrials/MyEJB1!edu.in.ejbinterfaces. RemoteEJB1?stateful");

    ejb1.startTransaction();
    RemoteEJB2 ejb2 = ejb1.getEJB2();
    ejb2.insertElement (“Test”);
    RemoteEJB3 ejb3 = ejb2.getEJB3();
    ejb3.updateElement (“UpdatedTest”);
    ejb1.commitTransaction();
}
}

I would ideally like the whole transaction(record insertions in db) to be completed after invocation of commitTransaction() on RemoteEJB1 bean.

I tried combination of BMT for EJB1 and CMT for EJB2 and EJB3 which lead to EJBTransactionRequiredException being thrown I tried to make all beans as BMT. However according to EJB3.1 spec BMT cannot be propagated across multiple beans. Could you let me know of any ideas/links which I could use to solve this problem?

Reference Application Server : JBOSS AS 7.1

1
How is the server supposed to link ejb1 with ejb2 instances? True, they have the same authenticated user, but as far as the server knows they could be being called from completely different, unrelated programs. You will need to call the ejb2 and ejb3 methods through ejb1. - SJuan76
EJB1,EJB2,EJB3 represent interfaces and objects of a standard API specification. Hence the contract for the methods is bound and I dont have leeway in terms of change. One major requirement from the API spec is the possibility of the model and interface implementation to be supportive of transaction and the transaction control would rest with the end user of my output - Pramod Kumar
I know it. The question is that the server does neither know your code nor have another way to know that the different beans are logically related, so it does not know if they are part of the same transaction of not. You can manage the transaction inside a stateful EJB because then the server knows that the methods are related (because you are using the same EJB). - SJuan76

1 Answers

0
votes

Could you let me know of any ideas/links which I could use to solve this problem?

If I understand your issue correctly, wath you need is called Client-Managed trasaction demarcation. UnLike Container Maneged Transaction, in this case the client is responsable to set the transaction boundaries (start and commit/rollback the transaction). You can get some ideas of how to implement it here.