GeeCON Prague 2014*
The moose likes EJB and other Java EE Technologies and the fly likes Should Bean developer throw RemoteException & related stuff Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


JavaRanch » Java Forums » Java » EJB and other Java EE Technologies
Bookmark "Should Bean developer throw RemoteException & related stuff" Watch "Should Bean developer throw RemoteException & related stuff" New topic
Author

Should Bean developer throw RemoteException & related stuff

Pho Tek
Ranch Hand

Joined: Nov 05, 2000
Posts: 761

Read talipozturk's blog item for context.

This sample session bean code from the JONAS project throws RemoteExceptions from its business methods for every type of errors it encounters e.g. null parameter, inability to persist.

Q1) Is this the correct use of RemoteException ? I'd thought that Bean developers should not throw SystemExceptions (RuntimeExceptions etc.. and also RemoteExceptions) ?

Q2) When should we (BeanDevelopers) use ApplicationExceptions (checked exceptions) ? Richard Monson-Haefel's oreilly book on EJB2 defines ApplicationExceptions as
An application exception must never extend either the RuntimeException, the RemoteException, or one of their subtypes.
Also, specifically he says:
An application exception is normally thrown in response to a business-logic error, as opposed to a system error. Application exceptions are always delivered directly to the client, without being repackaged as RemoteException or EJBException (EJB 2.0) types. They do not typically cause transactions to roll back; the client usually has an opportunity to recover after an application exception is thrown

If I understand this correctly, I can throw ApplicationExceptions right before any calls to the DB. Because after that point, a transaction would have been started.

Pho


Regards,

Pho
Roger Chung-Wee
Ranch Hand

Joined: Sep 29, 2002
Posts: 1683
This sample session bean code from the JONAS project throws RemoteExceptions from its business methods for every type of errors it encounters e.g. null parameter, inability to persist.

Q1) Is this the correct use of RemoteException ? I'd thought that Bean developers should not throw SystemExceptions (RuntimeExceptions etc.. and also RemoteExceptions) ?

The container must only receive non-application exceptions, eg RuntimeException, and errors from the bean. There are two ways this can happen.

1. If the bean method encounters a RuntimeException or error, it ducks it so that it propogates to the container.

2. If the bean method throws a checked exception that the bean method cannot recover, the bean method should encapsulate the exception in javax.ejb.EJBException (which is then thrown to the container).

When the Container catches a non-application exception from the bean, it does the following.
Logs it
Mark the transaction for rollback
Discards the instance
Throws the java.rmi.RemoteException (or subclass thereof) to the client if the client is a remote client, or throws the javax.ejb.EJBException (or subclass thereof) to the client if the client is a local client. This only applies to session and entity beans as message-driven beans to not have clientsIn summary, it is the container which throws RemoteException, never the bean.

Q2) When should we (BeanDevelopers) use ApplicationExceptions (checked exceptions) ?

The bean method should throw the appropriate application exception to report a business logic exception to the client. It does not automatically result in marking the transaction for rollback because the client is expected to be able to recover from it.

If I understand this correctly, I can throw ApplicationExceptions right before any calls to the DB. Because after that point, a transaction would have been started.

No, it does not work that way. Consider two methods: foo() and bar(). Let's say that foo() starts a transaction and calls bar() to update the database. Let's also say that the transaction attributes are Required, so bar() is running in foo()'s transaction. If bar() encounters a problem, the Bean Provider must ensure that either of the following must take place.

1. Ensure that the instance is in a state such that a client´┐Żs attempt to continue and/or commit the transaction does not result in loss of data integrity. Typically, the instance throws an application
exception before the instance performed any database updates.

2. Mark the transaction for rollback using the EJBContext.setRollbackOnly() method before throwing an application exception. Marking the transaction for rollback will ensure that the transaction can never commit.

The container will pass the application exception to foo(), which then decides what to do with it. Note that the transaction is still running at this point, nothing has yet been committed or rolled back.


SCJP 1.4, SCWCD 1.3, SCBCD 1.3
Pho Tek
Ranch Hand

Joined: Nov 05, 2000
Posts: 761

Roger,

Thanks a lot for replying.

So in summary, Bean developers should never throw RemoteExceptions. But throwing EJBException is fair game in the context of unrecoverable situations.

The bean method should throw the appropriate application exception to report a business logic exception to the client. It does not automatically result in marking the transaction for rollback because the client is expected to be able to recover from it.

Based on my own understanding, recoverable exceptions usually indicate things like:
  • Illegal values for arguments to the method
  • Violation of business rules. e.g. You need to have 20000 points in your frequent flyer account, in order to obtain this cheap fare.

  • So in cases like these, I would throw an ApplicationException as the client can easily retry with different values. And if I want to guarantee that this can ever be committed, I will just call setRollBack() on the EJBContext. I think I get it now.
    If the bean method throws a checked exception that the bean method cannot recover, the bean method should encapsulate the exception in javax.ejb.EJBException (which is then thrown to the container).

    Over the weekend, I was browsing the BitterEJB book and found this snippet which is pretty helpful:

    And in my SLSB business methods, I would do:


    Thanks

    Pho
    Pho Tek
    Ranch Hand

    Joined: Nov 05, 2000
    Posts: 761

    I was revisiting the NestedException code I posted in my last message and a thought struck me. Why did Bruce Tate et al. (authors of Bitter EJB) let other RuntimeExceptions be thrown back as is to its clients ? Whereas all checked exceptions are wrapped inside the NestedException (which is RuntimeException itself).

    Secondly why subclass from RuntimeException and not EJBException ? EJBException conveys more precisely that the error took place in the EJB tier.

    Regards,

    Pho
    Karthik Guru
    Ranch Hand

    Joined: Mar 06, 2001
    Posts: 1209
    Why let other RuntimeExceptions be thrown back as is to its clients ? Whereas all checked exceptions are wrapped inside the NestedException (which is RuntimeException itself).


    I guess when using CMT, one way to rollback the transaction is to throw a runtime exception. That is the reason i think they wrapped the Checked exception in a runtime exception and threw it back.
    Pho Tek
    Ranch Hand

    Joined: Nov 05, 2000
    Posts: 761

    If I get a NPE in my business method, I would want to wrap it up inside NestedException or EJBException also, no? But in the code for NestedException, an NPE will be thrown back to the client as is (specifically wrapped inside a RemoteException if its a remote method).

    An additional question, inside an SLSB business method e.g.:

    I can never come up with a better exception handling mechanism than the one shown above. There doesn't seem to be any reasons to catch specific exceptions. The catch-all suffices. Do you agree ? Compare with the convoluted solution described in this article

    Regards,

    Pho
    Karthik Guru
    Ranch Hand

    Joined: Mar 06, 2001
    Posts: 1209
    I agree that you cannot do anything even if you get a null pointer exception other than showing the user some decent message.

    But if you are throwing EJBException from the session facade for any kind of server side exception, you might end up with a code like this on the web tier?



    IMO, The above code looks a little uglier than



    So I would still catch Application specific exception on the session bean, log it if not done already , mark the transaction for rollback and re-throw it as it is. RuntimeExceptions will anyways propogate to the web tier, and mark the transaction for rollback as well. The web-tier can catch the such Exception s as a last option and show some generic message to the user.
    Pho Tek
    Ranch Hand

    Joined: Nov 05, 2000
    Posts: 761

    Karthik,

    I guess sometimes I just have a tendency to want to simplify things i.e. throw a specific exception that identifies the exception came from a particular layer in the typical J2EE architecture. (re: Joshua Bloch's item 43 => Throw Exceptions appropriate to the abstraction, i.e. higher layers should catch lower-level exceptions and, in their place, throw exceptions that are explainable in terms of higher-level abstraction)



    So based on your suggestion, this is what I propose:

  • Hibernate tier will throw a checked exception. Instead of wrapping it in EJBException, I will wrap it in a subclass of EJBException. e.g. PersistentTierException.
  • Any runtime exceptions like NPE, other EJB container exceptions will be thrown as is.
  • Delegates will throw everything as is (of course after dereferencing from RemoteExceptions if the session facade layer is distributed)
  • In the Command layer, I will be able to (a) retry/recover if I get an ApplicationException or (b) handle the runtime exceptions by showing relevant messages to the client.

  • What's to note: from the SLSB layer, I will throw a subclass of EJBException (not a subclass of RuntimeException)
    [ June 10, 2004: Message edited by: Pho Tek ]
     
    GeeCON Prague 2014
     
    subject: Should Bean developer throw RemoteException & related stuff