views:

544

answers:

2

Hi all,

I have an EJB3 application which consists of some EJB's for accessing a DB, and exposed via a Session Bean as a web service.

Now there are two things I need to find out:

1) Is there any way I can stop SQL exceptions from causing the web service from throwing a SOAP Fault? The transactions are handled by the container, and currently sql exceptions cause a RollBackException to be thrown, and consequently the transaction to be rolled back (desired behaviour) and the web service to throw a fault (not desired).

2) I wish to extend the webservice to be able to take in a list of entities, and the session bean to persist each. However, I want each entity to be executed in its own transaction, so that if one fails the others are not affected (and again the web service should not fault).

For (1) I have tried to catch the RollBackException, but I assume this is thrown somewhere on another thread, as the catch block is never reached. I assume for (2) I will need to look into User Transactions, but firstly would prefer the container to manage this, and secondly do not know how to force the use of user transactions.

Thanks.

A: 

For (1): Debug your code to find out where the exception is being thrown and what is causing it. Then handle the exception there.

For (2): Wrap each instance with beginTransaction() and commit().

for(each Entity){
    try{
        //begin transaction
        //save entity
        //commit
    } catch(Exception e) {
         //handle Exception, but continue on
    }
}
Kevin Crowell
As I said - the exception seems to be being thrown from a separate thread - or at least after my code has finiished what it is doing. Specifically, my code has returned control to the App server by the time the exception is thrown - i.e. it is not possible to catch it.
Ant
On the second point, I am quite aware of the general solution to this sort of problem - just not the specifics of how to do it in EJB3. How do I begin and commit transactions using the EntityManager? How do I get hold of an EntityManager which isn't bound to a container managed transaction?
Ant
+1  A: 

no, you can do all this with container managed transactions (and this is definitely preferable, as managing transactions is a pain).

the gist of the solution is to create a second EJB with a local interface only and the transaction semantics you desire. then your "public" ejb, which the web-service is calling directly, calls into this second ejb via its local interface to do the actual work.

something along the lines of:

public class MyPublicEjb {
  @EJB
  private MyPrivateImpl impl;

  public void doSomething() {
    try {
      impl.doSomething();
    } catch(TXRolledBack) {
      // handle rollback ...
    }
  }
}

I know this looks sort of ugly, but trust me, this is far preferable to directly manipulating transactions.

james
With the caveat that the private EJB required a @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) annotation (otherwise we have the same situation as before as the transaction is scoped on the calling EJB) this worked. Thanks.
Ant