001 package org.springframework.richclient.exceptionhandling;
002
003 import org.springframework.beans.factory.InitializingBean;
004 import org.springframework.context.support.MessageSourceAccessor;
005 import org.springframework.richclient.application.Application;
006 import org.springframework.richclient.application.ApplicationServicesLocator;
007 import org.springframework.richclient.application.ApplicationWindow;
008
009 import javax.swing.*;
010
011 /**
012 * Logs a throwable and shows a dialog about it to the user.
013 * @author Geoffrey De Smet
014 * @since 0.3
015 */
016 public abstract class AbstractDialogExceptionHandler extends AbstractLoggingExceptionHandler
017 implements InitializingBean {
018
019 private static final String DIALOG_EXCEPTION_HANDLER_KEY = "dialogExceptionHandler";
020
021 protected MessageSourceAccessor messageSourceAccessor;
022
023 protected boolean modalDialog = true;
024 protected ShutdownPolicy shutdownPolicy = ShutdownPolicy.ASK;
025
026 public void setMessageSourceAccessor(MessageSourceAccessor messageSourceAccessor) {
027 this.messageSourceAccessor = messageSourceAccessor;
028 }
029
030 /**
031 * Where or not the shown dialog should be modal (see JDialog API).
032 * The default is true;
033 * @param modalDialog
034 */
035 public void setModalDialog(boolean modalDialog) {
036 this.modalDialog = modalDialog;
037 }
038
039 /**
040 * Wheter or not the user should be asked or obligated to shutdown the application.
041 * The default is ASK.
042 * @param shutdownPolicy
043 */
044 public void setShutdownPolicy(ShutdownPolicy shutdownPolicy) {
045 this.shutdownPolicy = shutdownPolicy;
046 }
047
048 public void afterPropertiesSet() {
049 if (messageSourceAccessor == null) {
050 messageSourceAccessor = (MessageSourceAccessor)
051 ApplicationServicesLocator.services().getService(MessageSourceAccessor.class);
052 }
053 }
054
055
056 public void notifyUserAboutException(Thread thread, Throwable throwable) {
057 Object[] options;
058 // TODO implement ability to deal with mnemonics (for example "&Shutdown" in messages.properties)
059 switch (shutdownPolicy) {
060 case NONE:
061 options = new String[]{
062 messageSourceAccessor.getMessage(DIALOG_EXCEPTION_HANDLER_KEY + ".none.ok")};
063 break;
064 case ASK:
065 options = new String[]{
066 messageSourceAccessor.getMessage(DIALOG_EXCEPTION_HANDLER_KEY + ".ask.shutdown"),
067 messageSourceAccessor.getMessage(DIALOG_EXCEPTION_HANDLER_KEY + ".ask.continue")};
068 break;
069 case OBLIGATE:
070 options = new String[]{
071 messageSourceAccessor.getMessage(DIALOG_EXCEPTION_HANDLER_KEY + ".obligate.shutdown")};
072 break;
073 default:
074 // Can not occur and if it does it will crash the event thread
075 throw new IllegalStateException("Unrecognized shutdownPolicy: " + shutdownPolicy);
076 }
077 int result = JOptionPane.showOptionDialog(
078 resolveParentFrame(),
079 createExceptionContent(throwable),
080 resolveExceptionCaption(throwable),
081 JOptionPane.DEFAULT_OPTION,
082 resolveMessageType(), null,
083 options, options[0]);
084 if ((shutdownPolicy == ShutdownPolicy.ASK && result == 0)
085 || shutdownPolicy == ShutdownPolicy.OBLIGATE) {
086 logger.info("Shutting down due to uncaught exception.");
087 try {
088 if (Application.isLoaded()) {
089 Application.instance().close(true, 1);
090 }
091 } finally {
092 // In case the instance() method throws an exception and an exit didn't occur
093 System.exit(2);
094 }
095 }
096 }
097
098 protected JFrame resolveParentFrame() {
099 ApplicationWindow activeWindow = Application.isLoaded() ? Application.instance().getActiveWindow() : null;
100 return (activeWindow == null) ? null : activeWindow.getControl();
101 }
102
103 public abstract Object createExceptionContent(Throwable throwable);
104
105 public abstract String resolveExceptionCaption(Throwable throwable);
106
107 private int resolveMessageType() {
108 switch (logLevel) {
109 case TRACE:
110 case DEBUG:
111 case INFO:
112 return JOptionPane.INFORMATION_MESSAGE;
113 case WARN:
114 return JOptionPane.WARNING_MESSAGE;
115 case ERROR:
116 case FATAL:
117 default:
118 return JOptionPane.ERROR_MESSAGE;
119 }
120 }
121
122 }