Application Exceptions

   

System Exceptions

Any exception condition or error that isn't an application exception is a system exception. This means that system exceptions are instances of RuntimeException , RemoteException , Error , and their subclasses. These exceptions report unexpected low-level problems that aren't related to the application logic. Problems such as an inability to communicate with another EJB or an error obtaining a database connection are reported using system exceptions.

Other than RemoteException and its subclasses, system exceptions are unchecked exceptions, so you're not expected to catch the majority of them. As you were reminded earlier, an unchecked exception represents a problem that either shouldn't happen in a correct program or is severe enough that there's no expectation that you're able to recover from it. The handling of these exceptions in an EJB environment is quite different from that in a standalone application however. In a simple application, a response to an unexpected and severe error might simply be to exit the program (hopefully somewhat gracefully) and let the user retry what was being attempted once the external problem has been corrected. It's not a great answer, but sometimes you can't do much more for some underlying problems. Of course, a "raise the white flag" approach like this would likely land you on the street if you proposed it for an enterprise application. The systems that drive businesses can't anticipate unexpected errors any better than a small desktop application, but they have to be able to withstand them.

Perhaps the worst side effect of unexpected errors is that they are likely to leave object attributes and possibly database entries in an inconsistent state. This strikes at the core of what is demanded from an enterprise system. When unexpected errors occur, consistency must somehow be restored if it's been compromised. Left on your own to accomplish this, it's a formidable task for an application developer. Fortunately, one of the requirements set forth for EJB containers is that they must take responsibility for cleaning up any inconsistency introduced by a system exception. Because you're not expected to be able to recover from a system exception, there's no reason to stop the container from interceding and doing whatever cleanup is needed before you even see a system exception. Obviously, this is one of the primary advantages of building a system using EJB.

The Standard EJB System Exceptions

Just as with application exceptions, there are several standard system exceptions defined by the J2EE API. The most important system exceptions are RemoteException and EJBException . These exceptions differ from the application exceptions covered in this chapter in that they're much more general. In addition, system exceptions, unlike application exceptions, are reported differently to remote and local clients . This section describes each of the standard system exceptions and what they're used to report.

RemoteException

A remote client's calls to an enterprise bean are remote calls and a system-level failure is always a possibility during a remote call. Such problems are reported using java.rmi.RemoteException , which is unique among system exceptions. RemoteException and its subclasses are the only system exceptions that are checked exceptions. These exceptions report nonapplication errors just like the other system exceptions, but the problems they report can occur when correctly executing code runs into a problem outside the application's control. Just as an application can encounter an IOException when accessing an external resource, a remote client can encounter a RemoteException when accessing a server across the network. For this reason, RemoteException always needs to be handled by the caller.

RemoteException is used in many situations to report errors to a remote client, but it is never used with local clients.

As you've seen in previous chapters, you have to include RemoteException in the throws clause of every method you declare in a remote home or remote interface. A RemoteException can be thrown by the container or even by the communication subsystem that connects a client to the container. Because RemoteException is used to report communications problems anywhere along the path between a client and a bean instance, it's not possible for a caller to know if a method call was executed when this exception is thrown.

RemoteException provides the standard no-argument and message string constructors, and it also supports wrapping a nested exception:

 public RemoteException(String msg, Throwable nestedException) 

In the descriptions of the standard application exceptions earlier in this chapter, you saw that, even though some method declarations in a home interface are required to include a particular application exception, you're not always required to include it in the throws clause of the method implementation. For example, a create method must be declared to throw CreateException , but the corresponding ejbCreate method has no requirement to do the same. The requirements for RemoteException take this thought a step further. Not only are you not required to include RemoteException in the throws clauses for your method implementations , you're specifically directed not to.

RemoteException is used by the container to report problems to remote clients, but it's not the exception you as a bean provider should throw from your methods to indicate nonapplication exceptions. A RemoteException doesn't apply to a local client, so it doesn't make sense as an error-reporting choice for an implementation class. Instead, use EJBException , which is described next , or a suitable RuntimeException . The EJB 1.0 Specification defined the use of RemoteException to report system exceptions from bean methods, but this practice was deprecated in EJB 1.1 with preference given to the use of EJBException . EJB 2.0 still requires containers to support the deprecated use of RemoteException for this purpose, but you should avoid it. If you do throw a RemoteException from a bean method, the container will treat it just like an EJBException .

EJBException

An EJB instance throws a javax.ejb.EJBException to the container to report an unexpected error condition. You should use EJBException to report nonapplication errors to the container from your business methods and callback methods such as ejbCreate and ejbPostCreate .

You can construct an EJBException object without any arguments or with a string message, but you'll use it most often to nest a checked exception that you want to throw to the container as a system exception:

 public EJBException(Exception nestedException) 

EJBException differs from RemoteException in two key respects. First, EJBException is a subclass of RuntimeException , making it an unchecked exception. Even if you implement a method that can throw an EJBException to report a system problem, you're not required to include this exception in the throws clause of your method declarations. Second, because EJBException isn't specific to remote access issues, it's an appropriate choice for reporting errors to local clients. When a low-level problem occurs that prevents a method call from a local client to an enterprise bean from completing, the container uses an EJBException (or one of its subclasses) to report the problem to the client instead of RemoteException .

NoSuchObjectException and NoSuchObjectLocalException

The java.rmi.NoSuchObjectException subclass of RemoteException reports an attempt to invoke a method on a remote object that no longer exists. The EJB container throws this exception when a method call is attempted on an entity bean that has been removed from the database or a session object that has been removed. Similarly, javax.ejb.NoSuchObjectLocalException , which is a subclass of EJBException , reports an attempt by a local client to access an entity or session bean that has been removed.

The use of these exceptions probably is simplest to understand in the case of an entity bean. For example, a NoSuchObjectLocalException would result if two instances of AuctionHouseBean obtained a reference to the local interface for a particular EnglishAuction entity object, one of the clients made a call to remove the auction, and the other client attempted to call the submitBid method on the interface reference it still held.

For a session bean, a NoSuchObjectException would result, for example, if a remote client made a call to a stateful session bean after the container had passivated the session object and then removed it after the timeout period expired . As you'll see later in this chapter, the container gets rid of a bean instance if it throws a RuntimeException . This means that if a remote client attempts to call a stateful session bean after that bean has thrown a RuntimeException , a NoSuchObjectException results.

Remember, NoSuchObjectException and NoSuchObjectLocalException apply only to situations in which a bean instance has been removed by the container and not simply passivated. If a client makes a call to a passivated instance, the container activates the instance and directs it to service the call.

NoSuchEntityException

javax.ejb.NoSuchEntityException is a subclass of EJBException that you or the container should throw to indicate that a call was made to ejbLoad , ejbStore , or a business method for an entity object that has been removed from the database. When this exception is thrown from a bean method and not caught, the container is expected to throw either a NoSuchObjectException or a NoSuchObjectLocalException to the client based on the type of client that initiated the call.

TransactionRequiredException and TransactionRequiredLocalException

You learned in Chapter 12 that if a method deployed with the Mandatory transaction attribute is called without a transaction context, the container throws an exception. If the caller is a remote client, the javax.transaction.TransactionRequiredException subclass of RemoteException is used. In the case of a local client, a javax.ejb.TransactionRequiredLocalException , which extends EJBException , is used.

Throwing System Exceptions

A primary purpose of this chapter is to help you understand what type of exception to throw from a bean method in a particular situation. First of all, it's important that you correctly choose between an application and a system exception so you can accurately report the nature and severity of a problem. When an application exception is appropriate, which one you throw is unimportant to the container because it treats them all the same. All that matters with an application exception is that it reports the problem to the client in a precise enough way to support recovery from the error. Reporting a system exception is more complicated because the container does some work for you when this type of exception is thrown. The following sections present some guidelines to follow when you're handling system exceptions.

Runtime Exceptions

Rather than catching a RuntimeException or error in a bean method, you should allow it to be thrown to the container (or rethrow it if you do catch it). When an EJB instance throws a RuntimeException , the container discards that instance and will no longer make calls to it. This is a safety precaution to prevent problems that might result from continuing to use an instance left in an inconsistent state by an exception. When an instance is discarded, references held by clients are still valid because the container can replace the discarded instance with another one. The only caveat to this is for stateful session beans because each client is served by a specific instance that holds the conversational state between the two. If a stateful session bean instance is discarded, the client's state data is lost. Whenever a RuntimeException is thrown to the container from an entity or session bean, it will be thrown to a remote client as either a RemoteException or a TransactionRolledbackException as explained in the next section. If the client is a local client, the container throws either EJBException or TransactionRolledbackLocalException .

Note

Whenever the container is described as discarding a bean instance, this isn't the same as the instance being placed back into the pool for later use. When an instance is discarded, any resources the instance obtained through resource factories are released and the instance is made available for garbage collection.


Subsystem Exceptions

If you catch a checked exception that your bean method cannot recover from, throw an EJBException that wraps it. This applies in particular to checked exceptions from other J2EE subsystems such as JDBC, JNDI, and JMS. Rather than throwing exceptions like SQLException , NamingException , and JMSException directly to a client, you should wrap them with an EJBException . Although these exceptions fit the definition of application exceptions based on their position in the exception class hierarchy, you should treat them as system exceptions if you cannot adequately handle them within your bean methods. You should report them to the container in a way similar to what is done in this code segment:

 try {   InitialContext ctx = new InitialContext();    return (EnglishAuctionHome)ctx.lookup("java:/comp/env/ejb/EnglishAuction");  }  catch (javax.naming.NamingException e) {   // wrap this exception with EJBException and throw it to the container    throw new EJBException(e);  } 

Note

The preceding example assumes that the reference being obtained is to a local home interface. Remember that you need to use PortableRemoteObject to narrow any remote references you obtain using JNDI.


This guideline for subsystem exceptions applies to handling a RemoteException as well. If a bean method makes a call to a remote object, it must either catch RemoteException or include it in its throws clause. Given that EJB 2.0 specifically states that you should report system exceptions using EJBException instead of RemoteException , you should avoid allowing a RemoteException to be thrown from your methods. Instead, catch RemoteException when invoking a method on a remote object and throw EJBException if a nonapplication problem occurs.

Other Unexpected Errors

You should report any other unexpected error condition by throwing an EJBException that you construct with a string message that describes the error. As an example, this guideline applies when you execute a SQL statement that completes without reporting an error but doesn't produce the expected result. You previously saw examples like the following of this in Chapter 6, "Bean-Managed Persistence":

 ...  con = getConnection();  stmt = con.prepareStatement("DELETE FROM auction WHERE id = ?");  stmt.setInt(1, id.intValue());  int rowsDeleted = stmt.executeUpdate();  if (rowsDeleted != 1) {   throw new EJBException("Error deleting auction " + id);  }  ... 

Throwing Exceptions from Message-Driven Beans

Unlike application exceptions, message-driven beans are allowed to throw system exceptions but you should avoid even doing this, if possible. This enterprise bean type can report a system exception from its onMessage , ejbCreate , or ejbRemove methods as long as RemoteException isn't used. The specification explicitly prohibits a message-driven bean from throwing a RemoteException under any circumstance. It also states that a message-driven bean that throws a RuntimeException can't be considered a "well-behaved" JMS message listener. If a message-driven bean throws a RuntimeException from onMessage or any of its callback methods, the container destroys that instance of the bean. Clients are unaffected if this occurs because subsequent messages are simply delegated to other instances of the bean by the container.



Special Edition Using Enterprise JavaBeans 2.0
Special Edition Using Enterprise JavaBeans 2.0
ISBN: 0789725673
EAN: 2147483647
Year: 2000
Pages: 223

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net