// $HeadURL$ // $Id$ // // Copyright © 2006, 2010, 2011, 2012 by the President and Fellows of Harvard College. // // Screensaver is an open-source project developed by the ICCB-L and NSRB labs // at Harvard Medical School. This software is distributed under the terms of // the GNU General Public License. package edu.harvard.med.screensaver.ui.arch.view.aspects; import javax.persistence.OptimisticLockException; import org.apache.log4j.Logger; import org.aspectj.lang.ProceedingJoinPoint; import org.springframework.core.Ordered; import org.springframework.dao.ConcurrencyFailureException; import org.springframework.dao.DataAccessException; import edu.harvard.med.screensaver.ScreensaverConstants; import edu.harvard.med.screensaver.model.BusinessRuleViolationException; import edu.harvard.med.screensaver.model.DataModelViolationException; import edu.harvard.med.screensaver.service.OperationRestrictedException; import edu.harvard.med.screensaver.ui.arch.util.Messages; import edu.harvard.med.screensaver.ui.arch.view.AbstractBackingBean; import edu.harvard.med.screensaver.ui.arch.view.EditableEntityViewer; /** * Handles exceptions thrown by methods that are annotated * with {@link UICommand} by displaying an appropriate user error * message and then reloads the view with fresh data. */ public class UICommandExceptionHandlerAspect extends OrderedAspect implements Ordered { private static Logger log = Logger.getLogger(UICommandExceptionHandlerAspect.class); private Messages _messages; public void setMessages(Messages messages) { _messages = messages; } public Object invoke(ProceedingJoinPoint joinPoint) throws Throwable { try { return joinPoint.proceed(); } catch (OperationRestrictedException e) { return handleException(joinPoint, e, "restrictedOperation", e.getMessage()); } // catch the JPA exception for concurrency-related failures, since this is (apparently) what's being thrown, rather than the expected Spring-translated ConcurrencyFailureException // TODO: figure out why Spring-translated exceptions are not always/ever being thrown catch (OptimisticLockException e) { return handleException(joinPoint, e, "concurrentModificationConflict", null); } // catch the Spring-translated exception for concurrency-related failures catch (ConcurrencyFailureException e) { return handleException(joinPoint, e, "concurrentModificationConflict", null); } // catch the top-most (i.e., most general) Spring-translated exception for persistence-related failures catch (DataAccessException e) { return handleException(joinPoint, e, "databaseOperationFailed", e.getMessage()); } catch (BusinessRuleViolationException e) { return handleException(joinPoint, e, "businessError", e.getMessage()); } catch (DataModelViolationException e) { return handleException(joinPoint, e, "businessError", e.getMessage()); } catch (Throwable e) { log.error("",e); return handleException(joinPoint, e, "systemError", e.getMessage()); } } private Object handleException(ProceedingJoinPoint joinPoint, Throwable t, String errorMessageId, String errorMessageArg) { AbstractBackingBean backingBean = (AbstractBackingBean) joinPoint.getTarget(); log.error("backing bean " + backingBean.getClass().getSimpleName() + " method " + joinPoint.getSignature().getName() + " threw " + t.getClass().getSimpleName() + ": " + t.getMessage(), t); _messages.setFacesMessageForComponent(errorMessageId, null, errorMessageArg); if (backingBean instanceof EditableEntityViewer) { // TODO not working... // ((EntityViewer) backingBean).reload(); // this is the best we can do with the current design EditableEntityViewer editableViewer = (EditableEntityViewer) backingBean; return editableViewer.cancel(); } return ScreensaverConstants.REDISPLAY_PAGE_ACTION_RESULT; } }