001/* 002 * jDTAUS Core Messages 003 * Copyright (C) 2005 Christian Schulte 004 * <cs@schulte.it> 005 * 006 * This library is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 2.1 of the License, or any later version. 010 * 011 * This library is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with this library; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 019 * 020 */ 021package org.jdtaus.core.messages; 022 023import java.io.InvalidObjectException; 024import java.io.ObjectStreamException; 025import java.util.Locale; 026import org.jdtaus.core.container.ContainerFactory; 027import org.jdtaus.core.text.Message; 028 029/** 030 * {@code Message} stating that an exception occured. 031 * <p>The {@code Throwable} passed to the constructor of this class is used to 032 * determine the message's format arguments. For chained exceptions, that is, 033 * {@code getCause()} returns a non-{@code null} value, the root cause is used. 034 * </p> 035 * 036 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 037 * @version $JDTAUS: ExceptionMessage.java 8788 2012-12-03 02:15:13Z schulte $ 038 */ 039public final class ExceptionMessage extends Message 040{ 041 //--Constants--------------------------------------------------------------- 042 043 /** Serial version UID for backwards compatibility with 1.0.x classes. */ 044 private static final long serialVersionUID = 3771927969335656661L; 045 046 //---------------------------------------------------------------Constants-- 047 //--ExceptionMessage-------------------------------------------------------- 048 049 /** 050 * Throwable of the message. 051 * @serial 052 */ 053 private final Throwable throwable; 054 055 /** 056 * Root cause to report. 057 * @serial 058 */ 059 private Throwable rootCause; 060 061 /** 062 * Creates a new {@code ExceptionMessage} taking the {@code Throwable} to 063 * report. 064 * 065 * @param throwable the {@code Throwable} to report. 066 * 067 * @throws NullPointerException if {@code throwable} is {@code null}. 068 */ 069 public ExceptionMessage( final Throwable throwable ) 070 { 071 if ( throwable == null ) 072 { 073 throw new NullPointerException( "throwable" ); 074 } 075 076 Throwable current = throwable; 077 Throwable report = current; 078 while ( ( current = current.getCause() ) != null ) 079 { 080 report = current; 081 } 082 083 this.throwable = throwable; 084 this.rootCause = report; 085 } 086 087 //--------------------------------------------------------ExceptionMessage-- 088 //--Serializable------------------------------------------------------------ 089 090 /** 091 * Takes care of initializing the {@code rootCause} field when constructed 092 * from an 1.0.x object stream. 093 * 094 * @throws ObjectStreamException if no root cause can be resolved. 095 */ 096 private Object readResolve() throws ObjectStreamException 097 { 098 if ( this.throwable != null && this.rootCause == null ) 099 { 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 missing. 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}