4. Exception Handling
Exception Handling
The server exceptions can be handled on the client-side by defining a fault callback on each remote call. It works fine but it is very tedious and you can always forget a case, in which case the error will be either ignored or result in a Flex error popup that is not very elegant.
To help dealing with server exceptions, it is possible to define common handlers for particular fault codes on the client-side, and exception converters on the server-side, to convert server exceptions to common fault codes.
On the server, you have to define an ExceptionConverter class. For example we could write a converter to handle the JPA EntityNotFoundException (in fact there is also a built-in converter for all JPA exceptions):
public class EntityNotFoundExceptionConverter implements ExceptionConverter { public static final String ENTITY_NOT_FOUND = "Persistence.EntityNotFound"; public boolean accepts(Throwable t) { return t.getClass().equals(javax.persistence.EntityNotFoundException.class); } public ServiceException convert( Throwable t, String detail, Map<String, Object> extendedData) { ServiceException se = new ServiceException( ENTITY_NOT_FOUND, t.getMessage(), detail, t ); se.getExtendedData().putAll(extendedData); return se; } }
This class will intercept all EntityNotFound exceptions on the server-side, and convert it to a proper ENTITY_NOT_FOUND fault event.
This exception converter has to be declared on the GDS server config :
- When using scan="true" in granite-config.xml, ensure that there is a META-INF/granite-config.properties file (even empty) in the jar containing the exception converter class (same principle than the seam.properties file to specify which jars need to be scanned).
- When not using automatic scan, you can add this in granite-config.xml :
<exception-converters> <exception-converter type="com.package.SomeExceptionConverter"/> </exception-converters>
On the Flex side, you then have to define an exception handler class:
public class EntityNotFoundExceptionHandler implements IExceptionHandler {
public function accepts(emsg:ErrorMessage):Boolean {
return emsg.faultCode == "Persistence.EntityNotFound";
}
public function handle(context:BaseContext, emsg:ErrorMessage):void {
Alert.show("Entity not found: " + emsg.message);
}
}
... and register it as an exception handler for the Tide context in a static initializer block to be sure it is registered before anything else happens.
<mx:Application>
<mx:Script>
Seam.getInstance().addExceptionHandler(EntityNotFoundExceptionHandler);
</mx:Script>
</mx:Application>
