001: /*
002: * ThrowableMessageFormatter.java: formatting a throwable message
003: *
004: * Copyright (C) 2001 Heiko Blau
005: *
006: * This file belongs to the Susebox Java Core Library (Susebox JCL).
007: * The Susebox JCL is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as published by the
009: * Free Software Foundation; either version 2.1 of the License, or (at your
010: * option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful, but WITHOUT
013: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014: * FITNESS FOR A PARTICULAR PURPOSE.
015: * See the GNU Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public License along
018: * with the Susebox JCL. If not, write to the
019: *
020: * Free Software Foundation, Inc.
021: * 59 Temple Place, Suite 330,
022: * Boston, MA 02111-1307
023: * USA
024: *
025: * or check the Internet: http://www.fsf.org
026: *
027: * Contact:
028: * email: heiko@susebox.de
029: */
030:
031: package de.susebox.java.lang;
032:
033: //------------------------------------------------------------------------------
034: // Imports
035: //
036: import java.lang.reflect.Method;
037: import java.text.MessageFormat;
038: import de.susebox.java.lang.ThrowableList;
039:
040: //------------------------------------------------------------------------------
041: // Class ThrowableMessageFormatter
042: //
043:
044: /**<p>
045: * This class is used by the implementations of the {@link ThrowableList} interface.
046: * Its method {@link #getMessage} formats the message that should be returned by
047: * the {@link java.lang.Throwable#getMessage} overridden by implementations of the
048: * {@link ThrowableList} interface.
049: *</p>
050: *
051: * @see ThrowableList
052: * @see java.lang.Throwable
053: * @see java.text.MessageFormat
054: * @author Heiko Blau
055: */
056: public final class ThrowableMessageFormatter {
057:
058: /**
059: * Message indentation for nested exceptions.
060: */
061: public static final String MSG_IDENTATION = " ";
062:
063: /**
064: * This method should be called by all implementations of the {@link ThrowableList}
065: * interface in their {@link java.lang.Throwable#getMessage} implementation. It
066: * ensures that the formatting of throwable lists, nested or wrapped exceptions
067: * is done in a consistent way.
068: *<br>
069: * The method returns an throwable message assembled in this way:
070: *<ol><li>
071: * If the calling throwable is a wrapper throwable (see {@link ThrowableList#isWrapper}),
072: * it delegates the call to the wrapped throwable (<code>wrappedEx.getMessage()</code>).
073: *</li><li>
074: * If there is a nested throwable (the calling throwable has a message of its own),
075: * the returned message starts with the string returned by the {@link java.lang.Object#toString}
076: * method, followed and separated by a end-of-line sequence by the formatted message
077: * of the calling throwable.
078: *</li><li>
079: * If the calling throwable has only a message without parameters, this message
080: * is either appended to the string produced by processing a nested throwable or
081: * is taken as the entire return value if there is no nested or subsequent throwable
082: * present.
083: *</li><li>
084: * If the calling throwable provides parameters along with a format string (the
085: * return value of <code>super.getMessage</code> is interpreted as a format string),
086: * a formatted message produced by {@link java.text.MessageFormat#format} is either
087: * appended to the string produced by processing a nested throwable or is taken as
088: * the entire return value if there is no nested or subsequent throwable present.
089: *</li></ol>
090: *
091: * @param ex the calling throwable
092: * @return the formatted throwable message
093: * @see java.text.MessageFormat
094: * @see ThrowableList
095: */
096: public static final String getMessage(ThrowableList ex) {
097: // wrapped exceptions return theri own message
098: if (ex.isWrapper()) {
099: return ex.getCause().getMessage();
100: }
101:
102: // prepare the formatting
103: StringBuffer msg = new StringBuffer();
104: String fmt = ex.getFormat();
105: Throwable next = ex.getCause();
106:
107: // message of the nested or next throwable first
108: if (next != null) {
109: msg.append(EOL_SEQUENCE);
110: msg.append(MSG_IDENTATION);
111: msg.append(next.toString());
112: if (fmt != null) {
113: msg.append(EOL_SEQUENCE);
114: msg.append(MSG_IDENTATION);
115: }
116: }
117:
118: // and now our own message
119: if (fmt != null) {
120: Object[] args = ex.getArguments();
121:
122: if (args == null) {
123: msg.append(fmt);
124: } else {
125: try {
126: msg.append(MessageFormat.format(fmt, args));
127: } catch (IllegalArgumentException argEx) {
128: msg.append(argEx.getMessage());
129: msg.append(EOL_SEQUENCE);
130: msg.append("While formatting this message:");
131: msg.append(EOL_SEQUENCE);
132: msg.append(fmt);
133: }
134: }
135: }
136: return msg.toString();
137: }
138:
139: //---------------------------------------------------------------------------
140: // class constructor
141: //
142: static {
143: try {
144: Method causeMethod = Throwable.class.getMethod("getCause",
145: new Class[] {});
146: GET_CAUSE_AVAILABLE = true;
147: } catch (NoSuchMethodException ex) {
148: GET_CAUSE_AVAILABLE = false;
149: }
150: }
151:
152: //---------------------------------------------------------------------------
153: // members
154: //
155: private static final String EOL_SEQUENCE = System
156: .getProperty("line.separator");
157: private static boolean GET_CAUSE_AVAILABLE;
158: }
|