Donnerstag, 5. Februar 2009

Einfaches und Standardisiertes Exception Handling in Service Beans

Während der letzten beiden Jahre habe ich zu viele Service Klassen wie diese gesehen:

public LoginResponse handleLogin(LoginRequest request) {
 try {
  //Do something
 } catch (AuthenticationException e) {
    logger.warn("authentication exception", e);
    throw e;
 } catch (ServiceException e) {
    throw new ServiceException();
 } catch (Throwable e) {
    logger.fatal("Fatal error " + e.getMessage(), e);
    throw new ServiceException();
 }
}

public LogutResponse handleLogout(LogoutRequest request) {
 try {
  //Do something
 } catch (AuthenticationException e) {
    logger.warn("authentication exception", e);
    throw e;
 } catch (ServiceException e) {
    throw new ServiceException();
 } catch (Throwable e) {
    logger.fatal("Fatal error " + e.getMessage(), e);
    throw new ServiceException();
 }
}

public XYResponse handleXY(XYRequest request) {
 try {
  //Do something
 } catch (AuthenticationException e) {
    logger.warn("authentication exception", e);
    throw e;
 } catch (ServiceException e) {
    throw new ServiceException();
 } catch (Throwable e) {
    logger.fatal("Fatal error " + e.getMessage(), e);
    throw new ServiceException();
 }
}

//Think of plenty more methods like this one, all doing the same try catch stuff
Da ich copy&paste verabscheue habe ich nach einer Lösung für dieses Problem gesucht und im AOP Teil des Guice Frameworks gefunden: Da die meisten Service Beans einheitliche Exceptions werfen ist es ohne weiteres möglich auf das Try Catch in den Service Bean Methoden zu verzichten und diese in einen Interceptor zu packen. Dieser hat nur einen Methodenaufruf der mit einem Try Catch versehen wird, in dem alle relevanten Exceptions gefangen werden: Interceptor

//...
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
//...
public class ServiceXYExceptionInterceptor implements MethodInterceptor {
private static final Logger logger = Logger.getLogger(ServiceXYExceptionInterceptor.class);

public ServiceXYExceptionInterceptor() {
}

public Object invoke(MethodInvocation invocation) throws Throwable {
 try {
  return invocation.proceed();
 } catch (AuthenticationException e) {
  logger.warn("authentication exception", e);
  throw e;
 } catch (ServiceException e) {
  logger.error(MessageFormat.format("Service exception on {0} with params {1}", invocation.getMethod().getDeclaringClass(),
    Arrays.toString(invocation.getArguments())), e);
  throw e;
 } catch (Throwable e) {
  logger.fatal(MessageFormat.format("Unexpected Throwable on {0} with params {1}", invocation.getMethod().getDeclaringClass(),
    Arrays.toString(invocation.getArguments())), e);
  throw new ServiceException();
 }
}
}
The new Service Class

public LoginResponse handleLogin(LoginRequest request) {
  //Do something
  return response;
}

//Think of plenty more methods like this one, all ignoring the exceptions :-)
Damit man diese schicken Service Klassen auch sicher verwenden kann, muss der Interceptor noch mit Guice an die Service Bean gebastelt werden:

bindInterceptor(Matchers.subclassesOf(ServiceXY.class), Matchers.any(), new ServiceXYExceptionInterceptor());
Weitere Informationen zu diesem Thema sind unter folgenden Sites verfügbar: Tembrel's Tome - Injecting method interceptors in Guice 1.0 Guice Project Home

Kommentare:

rob hat gesagt…

} catch (ServiceException e) {
throw new ServiceException();
}


Für so etwas gibt's bei mir schonmal Nackenschläge...

Staenker hat gesagt…

Da wär ich nur noch am hauen...

  © Blogger template 'Morning Drink' by Ourblogtemplates.com 2008

Back to TOP