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    }