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 }