Discussions

EJB programming & troubleshooting: How to handle EJBException thrown from ejbStrore in client?

  1. If the updateCount of the update statment is zero in the ejbStore implementation, I want to inform the client about it so that a user-defined message can be displayed to the user.
    I cannot throw an application excpetion here because the ejbStore signature cannot be changed. I can throw an EJBException but the container intercepts this exception, rollsback the transaction and throws RemoteException to the client. In the process my EJBException (and the details) are lost. Is there anyway to handle this situation.

    Thanks in advance
    RD
  2. I suppose you can still get the EJBexception wrapped in RemoteException by calling re.detail in the try-catch block of client, where re is RemoteException thrown by EJB.

    re.detail returns a Throwable Object.

    I hope this helps.

    Nishchit




  3. I doubt the server will wrap the EJBException inside a RemoteException, because the EJBException is a server-side class. It is not defined as a part of the client interface, so the client may not have it's class definition (not necessarily EJBException - any exception that is or is linked to a RuntimeException, like SQLException wrapped inside an EJBException).
    There is no general solution to passing the client a specific exception from within ejbStore AFAIK, but your case (if I understand your problem) is so common it is addressed by the spec.
    If the update count in ejbStore is 0, i.e you didn't find anything to update, you should throw a NoSuchEntityException. This is a subclass of EJBException, and will cause the container to, aside from the normal effect, throw java.rmi.NoSuchObjectException to the client. You can catch this exception in your client and show the appropriate message.
    Note that I listed the case for remote interfaces. With local interfaces, NoSuchObjectLocalException is thrown to the client.

    Gal
  4. I am not sure exactly by your interpretation of server side class.

    If your client is running under JVM, the application class loader will ask the System Class loader to load EJBException class.(Its a part of java extension classes).So getting the definition doesn't seem to be a problem.

    You are right that user can throw NoSuchEntityException.But the container still handles the exception using the rules for EJBException. Only change is now NoSuchEntityException is wrapped in java.rmi.NoSuchObjectException(which is subclassed from RemoteException).

    The problem I understood was that user wants to pass some customized message from ejbStore through the Exception to the client.

    On the client side, you can check the wrapped exception type using 'instanceof' operator.

    Check if (re.detail instanceof javax.ejb.EJBException) is true or not, where 're' is RemoteException caught on client side.

    I checked it on Weblogic Server and it was true.

    Correct me if I am wrong.

    -Nishchit
  5. here is an example code to show you how to handle EJBException and related application exception http://www.myhtg.com/examples.zip
  6. I guess I was a little vauge in explaining why an EJB compliant server must not wrap an EJBException in a remote exception. Allow me to rephrase:
    The EJB spec defines a certain client interface classes that clients must know in order to use a remote EJB component. This client contract is important, because it defines which clients will be able to access the bean and which won't.
    You, as an EJB developper, can assume that the client has the remote and home interfaces and the classes used (transitively) by those interfaces. The App server can assume this, as well as assume that the client has some other classes defined by the EJB spec (e.g, javax.transaction.TransactionRolledBackException).
    The App server cannot assume a client has the EJBException class. EJB defines this class for an EJBs own use, not for clients. It does not mandate clients must have this class (just like clients don't need javax.ejb.EntityBean, for instance - it's only used by the bean itself).
    The problem goes beyond EJBException: first of all, the container throws a RemoteException for any RuntimeException you give it, and these RuntimeExceptions may be internal to the server. Second of all, even if the client does have EJBException, the EJBException can have another exception in it which may also be internal to the server and not available to the client.
    In order to keep EJBs client contract, the EJB server must not send classes to the client, that the client may not have. Note that this is not just a theoretical issue: in many deployment scenarios the client wont have EJBException. App servers usually generate a client jar for you, and I've never seen an App server put EJBException in that jar. And the client won't have the entire EJB extension locally - it's just a waste of space.

    I hope that clears my point.
    Gal
  7. My understanding goes like this,

    The idea of having a "detail" field of Throwable type in RemoteException class is to wrap the nested exception.

    Client don't need the wrapped exception type at the compile time. For him its just a throwable object type wrapped in RemoteException.

    Client can use any method exposed by Thowable class and getMessage() is among them.Client shouldn't use any EJBException specific methods.

    On the client side, we have code something like

    try{

    }catch(RemoteException re){
       re.detail.getMessage();
    }

    The above code is perfectly valid and client is not concerned of exact type of re.detail

    Again, correct me if I am wrong.

    -Nishchit
  8. Everything you said is true. The client does not need the nested throwable at compile-time. It does, however, need it at run time. The way Java serialization works, when the RemoteException is deserialized all it's fields are deserialized as well. The nested exception field is also deserialized, which consequently causes it's declaring class to be loaded.
    In a pure RMI system this would not pose a big problem, because codebase contexts travel with each RMI request. However, this does not work in EJB. First of all, EJBs must support RMI-IIOP based invocations, which cannot rely on dynamic loading. Further, even in the pure-RMI invocation case, EJB clients are not required to set up a security manager that allows remote class loading. In practice, I belive few EJB client applications have been coded with such support (set up something like RMISecurityManager, define policy files for remote code, etc).

    The problem I outlined in my posts above is that the Java serialization system will fail to deserialize the nested exception, causing a ClassNotFoundException wrapped inside an ObjectStreamException wrapped inside a RemoteException. This surely won't give you any meaningful details.
    Even if you do make sure you have all the classes the server might throw in your client, an EJB compliant Application server simply can't wrap system exceptions in a RemoteException, for the reasons listed above. What it could do is use the system exception's message as the RemoteException's message - but relying on this would be unportable.

    Gal
  9. Yeah, you are right.

    I thought EJBException class will be dynamically loaded on the client side.But the points you make out were correct.

    Thanks a lot.

    Nishchit
  10. Gal,

    As per your response, Java deserelialization will fail on client side for two reasons,

    1. Since EJB's are supporting RMI-IIOP based invocations, dynamic loading cannot be relied upon and client may not get all the required classes.

    My question is whether RMI-IIOP inhibits dynamic class loading? From whatever I can find out from FAQ's about RMI-IIOP, its clearly stated that RMI-IIOP supports it.

    2. RMISecurityManager is not setup on most of the clients and so dynamic classloading will not happen. I agree with this. But again, this is more to do with the flaw in writing the client. The server is not responsible for that.

    Can you throw more light on these issues?

    Thanks
    Nishchit
  11. I'll do my best :)

    1. RMI-IIOP itself does not inhibit dynamic class loading. However, a standard such as EJB cannot portably require clients to support dynamic class loading, even if RMI-IIOP supports it. The class has a binary format that suites one particular type of client (e.g, Java in this case). To achieve "CORBA portabillity" all CORBA clients must be able to access these classes, while currently the only environment where this is possible is Java. I estimate this will not change in the near future (5 years). Anyway, the point is: if you allowed dynamic class loading you would be narrowed down to Java clients, which defeats the entire point in supporting IIOP in the first place.

    2. EJB defines certain contracts that must be met by valid servers and clients. For instance, a valid EJB server must support IIOP 1.2. The question is, "are EJB clients required to allow dynamic class loading?". If they are not required to, a server cannot assume they will. Otherwise we would have portabillity problems where certain clients, that are valid to spec, won't be able to access certain EJBs. The answer to the question is "no, clients are not required to support dyanmic class loading" and the most inherent reason is that not all client *can* support dyanmic class loading (CORBA clients, client that run in limited JVMs, clients that don't have permissions to perform class loading, etc). I also pointed out that this issue is not unrelated to reality: most EJB clients probably don't support dynamic class loading. EJB should allow these clients to switch servers without changing their own code.

    I hope that clears it. Please post any unresolved issues.
    Gal
  12. I was waiting for your reply.

    Thanks again for your enlightment :)

    Nishchit
  13. No problem :)
    Thanks for consistently reviewing this discussion and my awfully vauge posts :) It helped us pin-down the important parts of this discussion.

    Gal