001 /* 002 * $Id: ErrorInfo.java 3100 2008-10-14 22:33:10Z rah003 $ 003 * 004 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021 022 package org.jdesktop.swingx.error; 023 024 import java.util.HashMap; 025 import java.util.Map; 026 import java.util.Properties; 027 import java.util.logging.Level; 028 029 import javax.swing.SwingUtilities; 030 031 /** 032 * <p>A simple class that encapsulates all the information needed 033 * to report a problem using the automated report/processing system.</p> 034 * 035 * <p>All HTML referred to in this API refers to version 3.2 of the HTML 036 * markup specification.</p> 037 * 038 * <p>Both basicErrorMessage and detailedErrorMessage may be specified with 039 * variable substitution. For example, this is a valid error message string: 040 * "${os.version} is not supported". Such variables are resovled using the 041 * <code>substituteVariables</code> method. This method will use properties in 042 * the "state" map to replace these variables.</p> 043 * 044 * <p>For example: 045 * <pre><code> 046 * String message = "An error occured on ${os.name} version ${os.version}"; 047 * //auto creates the state map, populated with all System properties. 048 * //Sandboxed apps can't read System properties. 049 * ErrorInfo info = new ErrorInfo("Error", exception); 050 * message = info.substituteVariables(message); 051 * 052 * //prints out: "An error occured on Mac OS X version 10.4.7" on some systems 053 * log.info(message); 054 * </code></pre></p> 055 * 056 * @status REVIEWED 057 * @author Alexander Zuev 058 * @author rbair 059 */ 060 public class ErrorInfo { 061 /** 062 * Short string that will be used as a error title 063 */ 064 private String title; 065 /** 066 * Basic message that describes incident 067 */ 068 private String basicErrorMessage; 069 /** 070 * Message that will fully describe the incident with all the 071 * available details 072 */ 073 private String detailedErrorMessage; 074 /** 075 * A category name, indicating where in the application this incident 076 * occurred. It is recommended that this be the same value as you 077 * would use when logging. 078 */ 079 private String category; 080 /** 081 * Optional Throwable that will be used as a possible source for 082 * additional information 083 */ 084 private Throwable errorException; 085 /** 086 * Used to specify how bad this error was. 087 */ 088 private Level errorLevel; 089 /** 090 * A Map which captures the state of the application 091 * at the time of an exception. This state is then available for error 092 * reports. 093 */ 094 private Map<String,String> state; 095 096 /** 097 * Creates a new ErrorInfo based on the provided data. 098 * 099 * @param title used as a quick reference for the 100 * error (for example, it might be used as the 101 * title of an error dialog or as the subject of 102 * an email message). May be null. 103 * 104 * @param basicErrorMessage short description of the problem. May be null. 105 * 106 * @param detailedErrorMessage full description of the problem. It is recommended, 107 * though not required, that this String contain HTML 108 * to improve the look and layout of the detailed 109 * error message. May be null. 110 * 111 * @param category A category name, indicating where in the application 112 * this incident occurred. It is recommended that 113 * this be the same value as you would use when logging. 114 * May be null. 115 * 116 * @param errorException <code>Throwable</code> that can be used as a 117 * source for additional information such as call 118 * stack, thread name, etc. May be null. 119 * 120 * @param errorLevel any Level (Level.SEVERE, Level.WARNING, etc). 121 * If null, then the level will be set to SEVERE. 122 * 123 * @param state the state of the application at the time the incident occured. 124 * The standard System properties are automatically added to this 125 * state, and thus do not need to be included. This value may be null. 126 * If null, the resulting map will contain only the System properties. 127 * If there is a value in the map with a key that also occurs in the 128 * System properties (for example: sun.java2d.noddraw), then the 129 * developer supplied value will be used. In other words, defined 130 * parameters override standard ones. In addition, the keys 131 * "System.currentTimeMillis" and "isOnEDT" are both defined 132 * automatically. 133 */ 134 public ErrorInfo(String title, String basicErrorMessage, String detailedErrorMessage, 135 String category, Throwable errorException, Level errorLevel, Map<String,String> state) { 136 this.title = title; 137 this.basicErrorMessage = basicErrorMessage; 138 this.detailedErrorMessage = detailedErrorMessage; 139 this.category = category; 140 this.errorException = errorException; 141 this.errorLevel = errorLevel == null ? Level.SEVERE : errorLevel; 142 this.state = new HashMap<String,String>(); 143 144 //first add all the System properties 145 try { 146 //NOTE: This is not thread safe because System.getProperties() does not appear 147 //to create a copy of the map. Thus, another thread could be modifying the System 148 //properties and the "state" at the time of this exception may not be 149 //accurate! 150 Properties props = System.getProperties(); 151 for (Map.Entry<Object, Object> entry : props.entrySet()) { 152 String key = entry.getKey() == null ? null : entry.getKey().toString(); 153 String val = entry.getKey() == null ? null : entry.getValue().toString(); 154 if (key != null) { 155 this.state.put(key, val); 156 } 157 } 158 } catch (SecurityException e) { 159 //probably running in a sandbox, don't worry about this 160 } 161 162 //add the automatically supported properties 163 this.state.put("System.currentTimeMillis", "" + System.currentTimeMillis()); 164 this.state.put("isOnEDT", "" + SwingUtilities.isEventDispatchThread()); 165 166 //now add all the data in the param "state". Thus, if somebody specified a key in the 167 //state map, it overrides whatever was in the System map 168 if (state != null) { 169 for (Map.Entry<String,String> entry : state.entrySet()) { 170 this.state.put(entry.getKey(), entry.getValue()); 171 } 172 } 173 } 174 175 /** 176 * Gets the string to use for a dialog title or other quick reference. Used 177 * as a quick reference for the incident. For example, it might be used as the 178 * title of an error dialog or as the subject of an email message. 179 * 180 * @return quick reference String. May be null. 181 */ 182 public String getTitle() { 183 return title; 184 } 185 186 /** 187 * <p>Gets the basic error message. This message should be clear and user oriented. 188 * This String may have HTML formatting, but any such formatting should be used 189 * sparingly. Generally, such formatting makes sense for making certain words bold, 190 * but should not be used for page layout or other such things.</p> 191 * 192 * <p>For example, the following are perfectly acceptable basic error messages: 193 * <pre> 194 * "Your camera cannot be located. Please make sure that it is powered on 195 * and that it is connected to this computer. Consult the instructions 196 * provided with your camera to make sure you are using the appropriate 197 * cable for attaching the camera to this computer" 198 * 199 * "<html>You are running on <b>reserver</b> battery 200 * power. Please plug into a power source immediately, or your work may 201 * be lost!</html>" 202 * </pre></p> 203 * 204 * @return basic error message or null 205 */ 206 public String getBasicErrorMessage() { 207 return basicErrorMessage; 208 } 209 210 /** 211 * <p>Gets the detailed error message. Unlike {@link #getBasicErrorMessage}, 212 * this method may return a more technical message to the user. However, it 213 * should still be user oriented. This String should be formatted using basic 214 * HTML to improve readability as necessary.</p> 215 * 216 * <p>This method may return null.</p> 217 * 218 * @return detailed error message or null 219 */ 220 public String getDetailedErrorMessage() { 221 return detailedErrorMessage; 222 } 223 224 /** 225 * Gets the category name. This value indicates where in the application 226 * this incident occurred. It is recommended that this be the same value as 227 * you would use when logging. This may be null. 228 * 229 * @return the category. May be null. 230 */ 231 public String getCategory() { 232 return category; 233 } 234 235 /** 236 * Gets the actual exception that generated the error. If this returns a 237 * non null value, then {@link #getBasicErrorMessage} may return a null value. 238 * If this returns a non null value and {@link #getDetailedErrorMessage} returns 239 * a null value, then this returned <code>Throwable</code> may be used as the 240 * basis for the detailed error message (generally by showing the stack trace). 241 * 242 * @return exception or null 243 */ 244 public Throwable getErrorException() { 245 return errorException; 246 } 247 248 /** 249 * Gets the severity of the error. The default level is <code>Level.SEVERE</code>, 250 * but any {@link Level} may be specified when constructing an 251 * <code>ErrorInfo</code>. 252 * 253 * @return the error level. This will never be null 254 */ 255 public Level getErrorLevel() { 256 return errorLevel; 257 } 258 259 /** 260 * <p>Gets a copy of the application state at the time that the incident occured. 261 * This map will never be null. If running with appropriate permissions the 262 * map will contain all the System properties. In addition, it contains two 263 * keys, "System.currentTimeMillis" and "isOnEDT".</p> 264 * 265 * <p>Warning: The System.properties <em>may not</em> contain the exact set 266 * of System properties at the time the exception occured. This is due to the 267 * nature of System.getProperties() and the Properties collection. While they 268 * are property synchronized, it is possible that while iterating the set of 269 * properties in the ErrorInfo constructor that some other code can change 270 * the properties on another thread. This is unlikely to occur, but in some 271 * applications <em>may</em> occur.</p> 272 * 273 * @return a copy of the application state. This will never be null. 274 */ 275 public Map<String,String> getState() { 276 return new HashMap<String,String>(state); 277 } 278 }