001/*
002 * $Id: ErrorInfo.java 4170 2012-02-21 14:27:15Z kleopatra $
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
022package org.jdesktop.swingx.error;
023
024import java.util.HashMap;
025import java.util.Map;
026import java.util.Properties;
027import java.util.logging.Level;
028
029import 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 * @status REVIEWED
039 * @author Alexander Zuev
040 * @author rbair
041 */
042public class ErrorInfo {
043    /**
044     * Short string that will be used as a error title
045     */
046    private String title;
047    /**
048     * Basic message that describes incident
049     */
050    private String basicErrorMessage;
051    /**
052     * Message that will fully describe the incident with all the
053     * available details
054     */
055    private String detailedErrorMessage;
056    /**
057     * A category name, indicating where in the application this incident
058     * occurred. It is recommended that this be the same value as you
059     * would use when logging.
060     */
061    private String category;
062    /**
063     * Optional Throwable that will be used as a possible source for
064     * additional information
065     */
066    private Throwable errorException;
067    /**
068     * Used to specify how bad this error was.
069     */
070    private Level errorLevel;
071    /**
072     *  A Map which captures the state of the application
073     *  at the time of an exception. This state is then available for error
074     *  reports.
075     */
076    private Map<String,String> state;
077    
078    /**
079     * Creates a new ErrorInfo based on the provided data.
080     *
081     * @param title                 used as a quick reference for the
082     *                              error (for example, it might be used as the
083     *                              title of an error dialog or as the subject of
084     *                              an email message). May be null.
085     *
086     * @param basicErrorMessage     short description of the problem. May be null.
087     *
088     * @param detailedErrorMessage  full description of the problem. It is recommended,
089     *                              though not required, that this String contain HTML
090     *                              to improve the look and layout of the detailed
091     *                              error message. May be null.
092     *
093     * @param category              A category name, indicating where in the application
094     *                              this incident occurred. It is recommended that
095     *                              this be the same value as you would use when logging.
096     *                              May be null.
097     *
098     * @param errorException        <code>Throwable</code> that can be used as a
099     *                              source for additional information such as call
100     *                              stack, thread name, etc. May be null.
101     *
102     * @param errorLevel            any Level (Level.SEVERE, Level.WARNING, etc).
103     *                              If null, then the level will be set to SEVERE.
104     *
105     * @param state                 the state of the application at the time the incident occured.
106     *                              The standard System properties are automatically added to this
107     *                              state, and thus do not need to be included. This value may be null.
108     *                              If null, the resulting map will contain only the System properties.
109     *                              If there is a value in the map with a key that also occurs in the
110     *                              System properties (for example: sun.java2d.noddraw), then the
111     *                              developer supplied value will be used. In other words, defined
112     *                              parameters override standard ones. In addition, the keys
113     *                              "System.currentTimeMillis" and "isOnEDT" are both defined
114     *                              automatically.
115     */
116    public ErrorInfo(String title, String basicErrorMessage, String detailedErrorMessage,
117            String category, Throwable errorException, Level errorLevel, Map<String,String> state) {
118        this.title = title;
119        this.basicErrorMessage = basicErrorMessage;
120        this.detailedErrorMessage = detailedErrorMessage;
121        this.category = category;
122        this.errorException = errorException;
123        this.errorLevel = errorLevel == null ? Level.SEVERE : errorLevel;
124        this.state = new HashMap<String,String>();
125        
126        //first add all the System properties
127        try {
128            //NOTE: This is not thread safe because System.getProperties() does not appear
129            //to create a copy of the map. Thus, another thread could be modifying the System
130            //properties and the "state" at the time of this exception may not be
131            //accurate!
132            Properties props = System.getProperties();
133            for (Map.Entry<Object, Object> entry : props.entrySet()) {
134                String key = entry.getKey() == null ? null : entry.getKey().toString();
135                String val = entry.getKey() == null ? null : entry.getValue().toString();
136                if (key != null) {
137                    this.state.put(key, val);
138                }
139            }
140        } catch (SecurityException e) {
141            //probably running in a sandbox, don't worry about this
142        }
143        
144        //add the automatically supported properties
145        this.state.put("System.currentTimeMillis", "" + System.currentTimeMillis());
146        this.state.put("isOnEDT", "" + SwingUtilities.isEventDispatchThread());
147        
148        //now add all the data in the param "state". Thus, if somebody specified a key in the
149        //state map, it overrides whatever was in the System map
150        if (state != null) {
151            for (Map.Entry<String,String> entry : state.entrySet()) {
152                this.state.put(entry.getKey(), entry.getValue());
153            }
154        }
155    }
156    
157    /**
158     * Gets the string to use for a dialog title or other quick reference. Used
159     * as a quick reference for the incident. For example, it might be used as the
160     * title of an error dialog or as the subject of an email message.
161     *
162     * @return quick reference String. May be null.
163     */
164    public String getTitle() {
165        return title;
166    }
167    
168    /**
169     * <p>Gets the basic error message. This message should be clear and user oriented.
170     * This String may have HTML formatting, but any such formatting should be used
171     * sparingly. Generally, such formatting makes sense for making certain words bold,
172     * but should not be used for page layout or other such things.</p>
173     *
174     * <p>For example, the following are perfectly acceptable basic error messages:
175     * <pre>
176     *      "Your camera cannot be located. Please make sure that it is powered on
177     *       and that it is connected to this computer. Consult the instructions
178     *       provided with your camera to make sure you are using the appropriate
179     *       cable for attaching the camera to this computer"
180     *
181     *      "&lt;html&gt;You are running on &lt;b&gt;reserver&lt;/b&gt; battery
182     *       power. Please plug into a power source immediately, or your work may
183     *       be lost!&lt;/html&gt;"
184     * </pre></p>
185     *
186     * @return basic error message or null
187     */
188    public String getBasicErrorMessage() {
189        return basicErrorMessage;
190    }
191    
192    /**
193     * <p>Gets the detailed error message. Unlike {@link #getBasicErrorMessage},
194     * this method may return a more technical message to the user. However, it
195     * should still be user oriented. This String should be formatted using basic
196     * HTML to improve readability as necessary.</p>
197     *
198     * <p>This method may return null.</p>
199     *
200     * @return detailed error message or null
201     */
202    public String getDetailedErrorMessage() {
203        return detailedErrorMessage;
204    }
205    
206    /**
207     * Gets the category name. This value indicates where in the application
208     * this incident occurred. It is recommended that this be the same value as
209     * you would use when logging. This may be null.
210     *
211     * @return the category. May be null.
212     */
213    public String getCategory() {
214        return category;
215    }
216    
217    /**
218     * Gets the actual exception that generated the error. If this returns a
219     * non null value, then {@link #getBasicErrorMessage} may return a null value.
220     * If this returns a non null value and {@link #getDetailedErrorMessage} returns
221     * a null value, then this returned <code>Throwable</code> may be used as the
222     * basis for the detailed error message (generally by showing the stack trace).
223     *
224     * @return exception or null
225     */
226    public Throwable getErrorException() {
227        return errorException;
228    }
229    
230    /**
231     * Gets the severity of the error. The default level is <code>Level.SEVERE</code>,
232     * but any {@link Level} may be specified when constructing an
233     * <code>ErrorInfo</code>.
234     *
235     * @return the error level. This will never be null
236     */
237    public Level getErrorLevel() {
238        return errorLevel;
239    }
240    
241    /**
242     * <p>Gets a copy of the application state at the time that the incident occured.
243     * This map will never be null. If running with appropriate permissions the
244     * map will contain all the System properties. In addition, it contains two
245     * keys, "System.currentTimeMillis" and "isOnEDT".</p>
246     *
247     * <p>Warning: The System.properties <em>may not</em> contain the exact set
248     * of System properties at the time the exception occured. This is due to the
249     * nature of System.getProperties() and the Properties collection. While they
250     * are property synchronized, it is possible that while iterating the set of
251     * properties in the ErrorInfo constructor that some other code can change
252     * the properties on another thread. This is unlikely to occur, but in some
253     * applications <em>may</em> occur.</p>
254     *
255     * @return a copy of the application state. This will never be null.
256     */
257    public Map<String,String> getState() {
258        return new HashMap<String,String>(state);
259    }
260}