i have two stateless ejb's Domain and Registration, each working with their own datasource. There is one situation where the domain calls the registration to update some stuff. If the registration fails, the updates in the domain sould be rolled back too. How can i achieve this, using BMT?
Start a user transaction in the domain before calling the registration. If you get back an exception from the registration, rollback.
In that case, what if i want the registration updates to succeed, but the domain updates to rollback?
In other words: how can i control if a BMT joins in an existing transaction, or ignores it, or has itws own transaction? You seem to say i automatically joins a running transaction.
I think my confusion is: if a CMT ejb did not start a transaction (for example because the called mehod was "Never"), why is it not allowed to use the UserTransaction inside the method?
Or in other words, it explained everywhere that you either have CMT or BMT, but in my view, CMT talks about how a running transaction is related to the ejb, while BMT talks about what to do if there is no running transactions. In that view, both have to coexist, but it's not allowed.
If you want the registration to succeed and the domain to rollback you should either make the domain start it's own transaction with RequiresNew, not start a user transaction before calling the registration and commit it right after the call returns (and then perhaps start a new transaction for the rest of the processing).
A BMT can't join an existing transaction. In the XA protocols, there is exactly one active party that has direct, synchronous control over the transaction: the initiator. This party can decide to synchronously commit or rollback. The other parties can vote for rollback or commit, but they can't decide when the transaction commits or rolls back. The transaction initiator can be either the container or the bean itself, but not both.
Your view (that methods with "Never" or "Supported" should be allowed to demarcate transactions directly) is valid, but it is not the view taken by the spec. This type of thing is likely to divide the bean class into two "logical" classes: one where you can (and have to) use UserTransaction, and when where you can rely on the container but you cannot use UserTransaction directly. This type of splitted transactional context is likely to lead to some comfusion, especially if you call the same method from two different parts, where one has user-demarcated transactions and the other has container-demarcated transactions.
The EJB spec resolves this comfusion by assigning each component (and thus each class) exactly one demarcation option. At least that is the rationale I see for it.
You say a BMT EJB will never be able to join a TX, but you explain why they can never decide to commit or rollback. But why can't it join?
A related confusion: say we're in a web application, no ejb's. I start a user transaction, and later on i start opening a connection to DS1, and later on one to DS2. As far as i understand, these connections somehow "automatically" register themselves with the TX. Great. There's no way to escape from it, no way to say "hey this DS2 should not be calculated in the transaction". Is that the way it is, or am i missing something.
If so, how can it be that ejb's can achieve that behaviour (choosing if their resources have to join the TX or not); ejb1 could be Required, while ejb2 could be NotSupported. What secrets are hidden from us developpers, but available to containers? UserTransaction.suspend()?
A BMT bean is by definition a bean that manages a transaction, not a bean that participates in one. The EJB spec could have defined it differently. The main reason it is defined this way, as far as I can tell, is that it would be quite hard to allow a BMT bean to participate in the caller's transaction and also retain transactional context between calls to a stateful session bean. Also, the operations allowed in a method would vary depending on whether or not the current transaction was started by the bean itself or not (for instance, UserTransaction.commit() would only work if the transaction was started by the bean). I think this reason was hinted somewhere in the spec or mailing list, but I don't remember exactly where.
A bean can "manage" a transaction it is participating in if it is using CMT. Particularly, it can mark a transaction for rollback. What other operations would you like to perform on a transaction you are participating in?
As for your second question, there is a difference between what the transaction system APIs allow you to do and what UserTransaction allows you to do. The javax.transaction API allows you to start and resume transactions, and also to manually register resources for a specified transaction (see Transaction.enlistResource()). When you are working in a managed environment using only UserTransaction, the container does the enlistment of resources itself, and you have no way to suspend a transaction (AFAIK). I don't know if there is a standard way to get the TransactionManager instance with which you can suspend/resume transactions, but many App servers allow you to get it through JNDI.
EJBs achieve this behaviour exactly like that: the container suspends a caller's transaction when entering a CMT method with RequiresNew or a BMT method, and starts (or resumes, in the case of a BMT stateful session bean that didn't finish it's transaction in the last call) another transaction. When the method call is finished, the container resumes the old transaction.
So, if a BTM can never join a transaction, you can never perform one transaction over 2 BMT ejb's, because in the second BTM ejb (called by the first one), the TX context of the first BMT will be "hidden", or suspended?