I have a method which throws an application exception with rollback true. I wonder if I have to explicitly call ejbContext.setRollbackOnly() or not?
The docs here says that we need not call the EjbContext's setRollbackOnly when the exception is marked as rollback=true.
In my case I catch a ApplicationException whose rollback attribute is set to true. Then I explicitly call ejbContext.setRollbackOnly() because I throw another exception in the catch block and this exception will be propagated to the client. Below is my code snippet
try {
....
} catch (XYZDirectoryException e) { // ApplicationException marked as rollback=true
ejbContext.setRollbackOnly(); // Is this necessary?
// log exception trace
throw new ServerInternalException("Something bad happened. Please try again or contact administrator. Check logs for more details"); // ApplicationException marked as rollback=false
}
An exception will not cause a rollback if it's thrown and caught inside a EJB transactional method. It has just to be thrown from a EJB transactional method in order to be caught by the transactional proxy around the EJB instance, otherwise, the container is completely unaware of the exception and thus won't rollback:
public void someEjbTransactionalMethod() {
// will cause a rollback
throw new XYZDirectoryException();
}
public void someOtheEjbTransactionalMethod() {
// will NOT cause a rollback
try {
throw new XYZDirectoryException();
}
catch (XYZDirectoryException) {
...
}
}
So, in your case, since the exception doesn't cross the boundary of any transactional EJB method, the container won't be aware of this exception, and won't rollback, unless you throw another "rollback=true" exception from the catch block, or explicitely mark the transaction as rollbackOnly.
Related
When using an ItemWriteListener (or similar) from Spring Batch, what is the correct way to handle checked exceptions thrown be delegates of the listener?
For example:
public class MyClass implements ItemWriteListener<MyDTO> {
// fields and constructor omitted
#Override
public void beforeWrite(List<MyDTO> items) {
try {
repository.loadAll(); // <-- Throws some checked exception
} catch (Exception e) {
// What to do here?
}
}
// other methods omitted
}
How should I handle that exception? Here are a few ideas:
Rethrow in a RuntimeException
Log the exception and let the step fail down the line where it depends on the action of this listener
Set some indicator on the MyDTO items to indicate a failure
Of course, I can't throw the checked exception, because it is not declared on the ItemWriteListener interface.
Throw a runtime exception, if the reader/writer depends on this action. This way, you can be sure that SpringBatch handles the transaction and the updates of the SpringBatch db-tables correctly.
I have an EJB Stateless Session Bean, like this:
public void persist(Customer customer,Child child){
try{
em.persist(customer);
Father father = new Father();
father.setChild(child); here child is null
em.persist(father);
}catch(Exception e){
}
}
When the exception (NullPointerException) occurs the transaction is not rolling back and Customer entity is persisted, but when i catch the exception with
public void persist(Customer customer,Child child){
try{
em.persist(customer);
Father father = new Father();
father.setChild(child); here child is null
em.persist(father);
}catch(EJBException e){
}
}
the transaction is rolling back, but i donĀ“t understand why, NullPointerException extends RuntimeException.The docs say a RuntimeException cause a rollback.
In the second example the NullPointerException is not caught, instead, you are catching an EJBException which is other runtime exception class.
As you say, when the Container intercepts the NullPointerException, the transaction is marked for rollback.
The first example catches Exception, wich is a base class (the Java exceptions are hierarchical ),
therefore, any subclass of Exception such as NullPointer or EJBException
is caught. In this case the Container doesn't mark the transaction for rollback.
I have EJB 2.0 legacy code. It has a session bean:
/**
* #ejb.bean
* name="Sample"
* type="Stateless"
* view-type="both"
* #ejb.transaction
* type="Required"
* #ejb.util
* generate="physical"
*/
public abstract class SampleEJB
implements SessionBean {
public void delete(Long id) {
EJBLocalObject local_o = getEjbLocalObject(id);
invokeDelete(local_o);
}
private void invokeDelete(EJBLocalObject local_o)
throws Exception
{
try
{
...
EJBLocalObject local_another_o = getEjbLocalObject(local_o.getAnotherId());
local_another_o.remove();
...
}
catch (Exception e)
{
// log exception
// throw new exception
}
try
{
...
local_o.remove();
...
}
catch (Exception e)
{
// log exception
// throw new exception
}
}
Sometimes due to issues in database, first remove call is successful. But second remove call fails and throws the exception.
This creates inconsistencies in database. Requirement is, all the remove calls should be successful. If one of the call fails, it should rollback the previous removes. How to handle such scenarios?
In case of BMT we can demarcate transactions for start, commit and rollback. But its CMT, so I am not sure how to handle this situation in EJB2.0. Please let me know what can be done.
#ejb.transaction * type="Required"
Assuming that this means the ejb transaction attribute configured is Requiered, the Container enforces that every call to delete() business method executes
within a transaction.
Therefore, to demarcate the transaction boundary is not a problem, you can be sure that both delete operations execute in the same transaction.
What you need is to mark the transaction for rollback if one delete operation fails.
The easier way to do this is that your business method throws a System exception.
} catch (Exception e) {
//log exception
throw new EJBException();
}
When the Container detects that a System exception (in ejb2.x this is exclusively an exception that extends from RuntimeException class) was thrown,
it automatically marks the transaction for rollback. However, when an Application Exception (an exception that extends from Exception) is thrown,
the Container doesn't change the transaction state.
In your case, it seems to be that delete() throws an Application Exception.
Other alternative is to explicitly marks the transaction for rollback using the SessionContext.setRollbackOnly() method.
//bean atribute
private SessionContext context;
//bean method call by the Container
public void setSessionContext(SessionContet ctx) {
context = ctx;
}
//your first delete code
try {
...
EJBLocalObject local_another_o = getEjbLocalObject(local_o.getAnotherId());
local_another_o.remove();
...
} catch (Exception e) {
context.setRollbackOnly();
//log exception
//throw new Exception
}
//idem for your second delete
I have a Java Class which does JNDI lookup and returns lookup ejb object. And if there is failure in lookup various exceptions are handled, when there is failure it will return null.
Now when that API is called and lookup fails we will get nullpointer exception. We can do a null check in calling class but I need exact reason for failure .. How to catch those exceptions thrown in base class?
Don't catch exceptions or if you need to catch them to do some specific work, rethrow them when done so the caller can see there was an exception and handle it itself too.
Like:
method1() {
try {
// SomeException is thrown here
} catch (SomeException e) {
// do some work because of the exception
throw e // re-throw or throw new MyException(e)
}
}
method2() {
try {
method1();
} catch (SomeException e) {
// something went bad!
// do some specific work?
}
}
If you want to transfer error information upwards in the call chain, the best way to do that is with an exception.
Instead of returning null on a failed look-up you should either let the look-up exception propagate up or wrap it in a custom exception if you want to add additional information.
I wonder what is the best way to catch an OptimisticLockException in JavaEE 6. I have the following EJB:
#Stateless
public class SeminarBooking {
public void bookSeminar(Long seminarId, int numberOfPersons) {
...
//check capacity & do booking
//OptimisticLockException can occur in this method
}
And this is my REST interface:
#Path("/seminars")
#Produces("application/xml")
#Stateless
public class SeminarResource {
#GET
#Path("{id}/book")
public Seminar bookSeminar(#PathParam("id") Long id, #QueryParam("persons") Integer persons) {
try {
seminarBooking.bookSeminar(id, persons);
return seminarBooking.getSeminar(id);
}
catch(Exception e) {
//why is this never called?
logger.error(This will never happen, e);
throw new WebApplicationException(e);
}
}
In the REST interface I catch all Exceptions, furthermore I see the OptimisticLockException if I call the interface from the browser, so why is the catch-Block never executed?
The obvious answer is that the exception in question isn't raised within that try block. Try reading the stack trace to see where it's thrown from. Given that it's related to persistence, it's likely thrown at your transaction boundary rather than from where you think it is.
It's probably never called because the SeminarResource is a transactional EJB. That means that the transaction is committed after its bookSeminar() method has returned, and not before it has returned.
This bean should probably not be transactional. If it weren't, the transaction would start when the SeminarBooking service is called, and commit when it returns. And you would be able to catch the exception that the commit throws.