1 /* 2 * jDTAUS Core Messages 3 * Copyright (C) 2005 Christian Schulte 4 * <cs@schulte.it> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 * 20 */ 21 package org.jdtaus.core.messages; 22 23 import java.io.InvalidObjectException; 24 import java.io.ObjectStreamException; 25 import java.util.Locale; 26 import org.jdtaus.core.container.ContainerFactory; 27 import org.jdtaus.core.text.Message; 28 29 /** 30 * {@code Message} stating that an exception occured. 31 * <p>The {@code Throwable} passed to the constructor of this class is used to 32 * determine the message's format arguments. For chained exceptions, that is, 33 * {@code getCause()} returns a non-{@code null} value, the root cause is used. 34 * </p> 35 * 36 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 37 * @version $JDTAUS: ExceptionMessage.java 8641 2012-09-27 06:45:17Z schulte $ 38 */ 39 public final class ExceptionMessage extends Message 40 { 41 //--Constants--------------------------------------------------------------- 42 43 /** Serial version UID for backwards compatibility with 1.0.x classes. */ 44 private static final long serialVersionUID = 3771927969335656661L; 45 46 //---------------------------------------------------------------Constants-- 47 //--ExceptionMessage-------------------------------------------------------- 48 49 /** 50 * Throwable of the message. 51 * @serial 52 */ 53 private final Throwable throwable; 54 55 /** 56 * Root cause to report. 57 * @serial 58 */ 59 private Throwable rootCause; 60 61 /** 62 * Creates a new {@code ExceptionMessage} taking the {@code Throwable} to 63 * report. 64 * 65 * @param throwable the {@code Throwable} to report. 66 * 67 * @throws NullPointerException if {@code throwable} is {@code null}. 68 */ 69 public ExceptionMessage( final Throwable throwable ) 70 { 71 if ( throwable == null ) 72 { 73 throw new NullPointerException( "throwable" ); 74 } 75 76 Throwable current = throwable; 77 Throwable report = current; 78 while ( ( current = current.getCause() ) != null ) 79 { 80 report = current; 81 } 82 83 this.throwable = throwable; 84 this.rootCause = report; 85 } 86 87 //--------------------------------------------------------ExceptionMessage-- 88 //--Serializable------------------------------------------------------------ 89 90 /** 91 * Takes care of initializing the {@code rootCause} field when constructed 92 * from an 1.0.x object stream. 93 * 94 * @throws ObjectStreamException if no root cause can be resolved. 95 */ 96 private Object readResolve() throws ObjectStreamException 97 { 98 if ( this.throwable != null && this.rootCause == null ) 99 { 100 Throwable current = this.throwable; 101 Throwable report = current; 102 while ( ( current = current.getCause() ) != null ) 103 { 104 report = current; 105 } 106 this.rootCause = report; 107 } 108 else if ( !( this.throwable != null && this.rootCause != null ) ) 109 { 110 throw new InvalidObjectException( 111 this.getMissingObjectStreamFieldMessage( this.getLocale() ) ); 112 113 } 114 115 return this; 116 } 117 118 //------------------------------------------------------------Serializable-- 119 //--Message----------------------------------------------------------------- 120 121 /** 122 * {@inheritDoc} 123 * <p>This method traverses up the chained hierarchy. The arguments 124 * returned are constructed using the root cause.</p> 125 * 126 * @return Strings describing the throwable. 127 * <ul> 128 * <li>[0]: the fully qualified classname of the root cause.</li> 129 * <li>[1]: the classname of the root cause without package.</li> 130 * <li>[2]: the message of the root cause.</li> 131 * </ul> 132 */ 133 public Object[] getFormatArguments( final Locale locale ) 134 { 135 String name = this.rootCause.getClass().getName(); 136 final int lastDot = name.lastIndexOf( '.' ); 137 138 if ( lastDot >= 0 ) 139 { 140 name = name.substring( lastDot + 1 ); 141 } 142 143 String message = this.rootCause.getMessage(); 144 if ( message == null ) 145 { 146 message = this.getNoDetailsAvailableMessage( locale ); 147 } 148 149 return new Object[] 150 { 151 this.rootCause.getClass().getName(), name, message 152 }; 153 } 154 155 /** 156 * {@inheritDoc} 157 * 158 * @return The corresponding text from the message's {@code ResourceBundle}: 159 * <blockquote><pre> 160 * An {1} occured. 161 * Details: {2} 162 * </pre></blockquote> 163 */ 164 public String getText( final Locale locale ) 165 { 166 String name = this.rootCause.getClass().getName(); 167 final int lastDot = name.lastIndexOf( '.' ); 168 169 if ( lastDot >= 0 ) 170 { 171 name = name.substring( lastDot + 1 ); 172 } 173 174 String message = this.rootCause.getMessage(); 175 if ( message == null ) 176 { 177 message = this.getNoDetailsAvailableMessage( locale ); 178 } 179 180 String text; 181 if ( this.rootCause instanceof Error ) 182 { 183 text = this.getErrorInfoMessage( locale, name, message ); 184 } 185 else 186 { 187 text = this.getExceptionInfoMessage( locale, name, message ); 188 } 189 190 return text; 191 } 192 193 //-----------------------------------------------------------------Message-- 194 //--Dependencies------------------------------------------------------------ 195 196 // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausDependencies 197 // This section is managed by jdtaus-container-mojo. 198 199 /** 200 * Gets the configured <code>Locale</code> implementation. 201 * 202 * @return The configured <code>Locale</code> implementation. 203 */ 204 private Locale getLocale() 205 { 206 return (Locale) ContainerFactory.getContainer(). 207 getDependency( this, "Locale" ); 208 209 } 210 211 // </editor-fold>//GEN-END:jdtausDependencies 212 213 //------------------------------------------------------------Dependencies-- 214 //--Messages---------------------------------------------------------------- 215 216 // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausMessages 217 // This section is managed by jdtaus-container-mojo. 218 219 /** 220 * Gets the text of message <code>exceptionInfo</code>. 221 * <blockquote><pre>Eine {0} ist aufgetreten. {1}</pre></blockquote> 222 * <blockquote><pre>A {0} occured. {1}</pre></blockquote> 223 * 224 * @param locale The locale of the message instance to return. 225 * @param exceptionName Name of the exception. 226 * @param exceptionMessage Message of the exception. 227 * 228 * @return Information about an exception. 229 */ 230 private String getExceptionInfoMessage( final Locale locale, 231 final java.lang.String exceptionName, 232 final java.lang.String exceptionMessage ) 233 { 234 return ContainerFactory.getContainer(). 235 getMessage( this, "exceptionInfo", locale, 236 new Object[] 237 { 238 exceptionName, 239 exceptionMessage 240 }); 241 242 } 243 244 /** 245 * Gets the text of message <code>errorInfo</code>. 246 * <blockquote><pre>Ein {0} ist aufgetreten. {1}</pre></blockquote> 247 * <blockquote><pre>A {0} occured. {1}</pre></blockquote> 248 * 249 * @param locale The locale of the message instance to return. 250 * @param errorName Name of the error. 251 * @param errorMessage Message of the error. 252 * 253 * @return Information about an error. 254 */ 255 private String getErrorInfoMessage( final Locale locale, 256 final java.lang.String errorName, 257 final java.lang.String errorMessage ) 258 { 259 return ContainerFactory.getContainer(). 260 getMessage( this, "errorInfo", locale, 261 new Object[] 262 { 263 errorName, 264 errorMessage 265 }); 266 267 } 268 269 /** 270 * Gets the text of message <code>noDetailsAvailable</code>. 271 * <blockquote><pre>Keine Details verfügbar.</pre></blockquote> 272 * <blockquote><pre>No details available.</pre></blockquote> 273 * 274 * @param locale The locale of the message instance to return. 275 * 276 * @return Information that no details are available. 277 */ 278 private String getNoDetailsAvailableMessage( final Locale locale ) 279 { 280 return ContainerFactory.getContainer(). 281 getMessage( this, "noDetailsAvailable", locale, null ); 282 283 } 284 285 /** 286 * Gets the text of message <code>missingObjectStreamField</code>. 287 * <blockquote><pre>Fehlende Felder im Datenstrom.</pre></blockquote> 288 * <blockquote><pre>Missing fields in object stream.</pre></blockquote> 289 * 290 * @param locale The locale of the message instance to return. 291 * 292 * @return Information that a field in an object stream is missong. 293 */ 294 private String getMissingObjectStreamFieldMessage( final Locale locale ) 295 { 296 return ContainerFactory.getContainer(). 297 getMessage( this, "missingObjectStreamField", locale, null ); 298 299 } 300 301 // </editor-fold>//GEN-END:jdtausMessages 302 303 //----------------------------------------------------------------Messages-- 304 }