001 package org.springframework.richclient.exceptionhandling; 002 003 import org.apache.commons.lang.StringUtils; 004 import org.apache.commons.lang.WordUtils; 005 import org.springframework.context.support.DefaultMessageSourceResolvable; 006 import org.springframework.core.ErrorCoded; 007 008 import java.util.ArrayList; 009 import java.util.List; 010 import java.util.StringTokenizer; 011 import java.sql.SQLException; 012 013 /** 014 * Displays a message to the user which is fetched from the I18N files 015 * based on the class and superclasses of the throwable. 016 * <p/> 017 * For example if an IllegalArgumentException is thrown, it will search for 018 * java.lang.IllegalArgumentException.caption and java.lang.IllegalArgumentException.description first, 019 * and if it cant find that it will try in order: 020 * java.lang.RuntimeException.caption/description, java.lang.Exception.caption/description and 021 * java.lang.Throwable.caption/description. 022 * <p/> 023 * The exception message is passed as a parameter, but is idented and wrapped first. 024 * Note for the repacing of {0} to work in a property file double quotes(") need to be escaped (\") 025 * and that single quotes (') should be avoided (escaping doesn't seem to work). 026 * @author Geoffrey De Smet 027 * @since 0.3 028 */ 029 public class MessagesDialogExceptionHandler extends AbstractDialogExceptionHandler { 030 031 private int wrapLength = 120; 032 private int identLength = 2; 033 034 private String messagesKey = null; 035 036 /** 037 * Sets the wrap length applied on the exception message passed as a parameter. 038 * Defaults to 120. 039 * @param wrapLength 040 */ 041 public void setWrapLength(int wrapLength) { 042 this.wrapLength = wrapLength; 043 } 044 045 /** 046 * Sets the identation applied on the exception message passed as a parameter. 047 * Defaults to 2. 048 * @param identLength 049 */ 050 public void setIdentLength(int identLength) { 051 this.identLength = identLength; 052 } 053 054 /** 055 * If messagesKey is set, the caption and description shown in the dialog 056 * are not based dynamically on the throwable, 057 * but instead statically on the keys messageKey.caption and messageKey.description. 058 * 059 * @param messagesKey the key used for the caption and title 060 */ 061 public void setMessagesKey(String messagesKey) { 062 this.messagesKey = messagesKey; 063 } 064 065 066 public String resolveExceptionCaption(Throwable throwable) { 067 String[] messagesKeys = getMessagesKeys(throwable, ".caption"); 068 return messageSourceAccessor.getMessage(new DefaultMessageSourceResolvable( 069 messagesKeys, messagesKeys[0])); 070 } 071 072 public Object createExceptionContent(Throwable throwable) { 073 String[] messagesKeys = getMessagesKeys(throwable, ".description"); 074 String[] parameters = new String[]{formatMessage(throwable.getMessage())}; 075 return messageSourceAccessor.getMessage(new DefaultMessageSourceResolvable( 076 messagesKeys, parameters, messagesKeys[0])); 077 } 078 079 private String[] getMessagesKeys(Throwable throwable, String keySuffix) { 080 if (messagesKey != null) { 081 return new String[] {messagesKey}; 082 } 083 List<String> messageKeyList = new ArrayList<String>(); 084 Class clazz = throwable.getClass(); 085 if(throwable instanceof ErrorCoded) 086 { 087 messageKeyList.add(((ErrorCoded) throwable).getErrorCode() + keySuffix); 088 } 089 if(throwable instanceof SQLException) 090 { 091 messageKeyList.add(SQLException.class.getName() + "." + ((SQLException) throwable).getErrorCode() + keySuffix); 092 } 093 while (clazz != Object.class) { 094 messageKeyList.add(clazz.getName() + keySuffix); 095 clazz = clazz.getSuperclass(); 096 } 097 return messageKeyList.toArray(new String[messageKeyList.size()]); 098 } 099 100 protected String formatMessage(String message) { 101 if (message == null) { 102 return ""; 103 } 104 String identString = StringUtils.leftPad("", identLength); 105 String newLineWithIdentString = "\n" + identString; 106 StringBuilder formattedMessageBuilder = new StringBuilder(identString); 107 StringTokenizer messageTokenizer = new StringTokenizer(message, "\n"); 108 while (messageTokenizer.hasMoreTokens()) { 109 String messageToken = messageTokenizer.nextToken(); 110 formattedMessageBuilder.append(WordUtils.wrap(messageToken, wrapLength, newLineWithIdentString, true)); 111 if (messageTokenizer.hasMoreTokens()) { 112 formattedMessageBuilder.append(newLineWithIdentString); 113 } 114 } 115 return formattedMessageBuilder.toString(); 116 } 117 118 }