The EJB control makes it easy to use an existing, deployed EJB from within an application. This topic describes how to handle exceptions that might be thrown by the target EJB or the EJB control itself.
If the target EJB method invoked via an EJB control throws a checked exception (that is, an exception that does not extend a RuntimeException), a try-catch block must catch the exception. It is generally considered a best practice to catch exceptions that occur within the EJB method (thrown by other methods the EJB method uses), and either overcome the exception or, when this is impossible, rethrow these exceptions either as an application exception or an EJBException, depending on whether the failure is due to a system-level or business logic error, and whether the transaction should be automatically rolled back.
An application exception is a checked exception that is either defined by the bean developer and does not extend a RemoteException, or is predefined in the javax.ejb package (that is, CreateException, DuplicateKeyException, FinderException, ObjectNotFoundException, or RemoveException). The EJB's method explicitly defines any application exception in the throws statement, and a try-catch block must catch the exception.
If the EJB control uses the EJB control's remote interfaces, a RunTimeException or an EJBException thrown by the EJB method is nested by the EJB container inside a RemoteException, and the RemoteException is propagated to the client. Because a RemoteException is a checked exception, the client must catch the exception. For more information on RemoteException, see your favorite J2EE reference documentation or the J2SE API documentation at http://java.sun.com. An example of catching a RemoteException is given below.
A java.lang.RuntimeException and its subtypes, including EJBException, can be thrown by an EJB method via its corresponding EJB control. Although these exceptions do not have to be explicitly caught in your code, it is generally a good idea to catch these exceptions in the client application invoking an EJB control, which uses the EJB's local interfaces. (Remember that for remote interfaces, the EJBException is rethrown by the EJB container as a RemoteException.)
As mentioned above, a checked exceptions caught in a bean method is often rethrown as an EJBException. You can checked for such a nested exception by invoking the getCause() or getCausedByException() methods on the caught EJBException. For more information on EJBException, see your favorite J2EE reference documentation or the J2EE API documentation at http://java.sun.com. An example of nesting and catching an exception through EJBException is given below.
The EJB control will throw a com.bea.ControlException when it has a problem locating/referencing the EJB. Although this is a subtype of RuntimeException and therefore does not have to be caught explicitly, it again might be a good idea to catch it in the client application. For more information, see the ControlException API.
The following example demonstrates the rethrowing of a checked exception inside an EJBException by an EJB method, and the catching of this exception on the client side. Rethrowing the exception inside an EJBException in the example is done solely to illustrate the mechanics of exception handling, and should not be considered recommended design. As mentioned above, checked exceptions should be rethrown either as an application exception or an EJBException, depending on whether the failure is due to a system-level or business logic error, and whether the transaction should be automatically rolled back.
The first code snippet shows the definition of the MusicBean method addRecording. Notice that FinderException, which can be thrown by findByPrimaryKey, is rethrown inside an EJBException, and that CreateException, which can be thrown by the BandBean's business method addThisRecording, is rethown inside an EJBException:
/** * @ejbgen:local-method * @ejbgen:remote-method */ public void addRecording(String band, String recording) { try { Band bandBean = bandHome.findByPrimaryKey(new BandPK(band)); if(bandBean != null) { bandBean.addThisRecording(recording); } } catch(CreateException ce) { throw (EJBException) new EJBException(ce).initCause(ce); } catch(FinderException fe) { throw (EJBException) new EJBException(fe).initCause(fe); } }
On the client side, the MusicBean's method is invoked via an EJB control, and an EJBException is caught and checked. If the client uses an EJB control that locates the EJB via its local interfaces, you can catch the EJBException directly and retrieve the nested exception. The following code snippet shows how this is done in a page flow's action method, using an EJB control that locates the EJB via its local interfaces:
/** * @common:control */ private EJBControls.MusicBeanControl library; ... /** * @jpf:action * @jpf:forward name="success" path="addRecording.jsp" */ protected Forward addARecording(AddARecordingForm form) { String recording = (form.getRecordingName()).trim(); String bandChoice = form.getSelectedBand(); if(recording.length() != 0) { try { library.addRecording(bandChoice, recording); allRecordings = library.getRecordings(bandChoice); } catch(EJBException ee) { Exception ne = (Exception) ee.getCause(); if(ne.getClass().getName().equals("FinderException")) ... else if(...) ... } } ... return new Forward("success"); }
If the client uses an EJB control that references the EJB via its remote interfaces, you must catch the RemoteException instead and retrieve its nested exception. The following code snippet shows how this is done:
/** * @common:control */ private EJBControls.RemoteMusicBeanControl remoteLibrary; ... /** * @jpf:action * @jpf:forward name="success" path="addRecording.jsp" */ protected Forward addARecording(AddARecordingForm form) { String recording = (form.getRecordingName()).trim(); String bandChoice = form.getSelectedBand(); if(recording.length() != 0) { try { remoteLibrary.addRecording(bandChoice, recording); allRecordings = library.getRecordings(bandChoice); } catch(RemoteException re) { EJBException ee = (EJBException) re.getCause(); Exception ne = (Exception) ee.getCause(); ... } } ... return new Forward("success"); }