source: josm/trunk/src/org/openstreetmap/josm/tools/BugReportExceptionHandler.java@ 1023

Last change on this file since 1023 was 914, checked in by stoecker, 16 years ago

fixed typo

  • Property svn:eol-style set to native
File size: 7.1 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.tools;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.GridBagLayout;
7import java.awt.Toolkit;
8import java.awt.datatransfer.Clipboard;
9import java.awt.datatransfer.ClipboardOwner;
10import java.awt.datatransfer.StringSelection;
11import java.awt.datatransfer.Transferable;
12import java.io.BufferedReader;
13import java.io.File;
14import java.io.InputStreamReader;
15import java.io.PrintWriter;
16import java.io.StringWriter;
17import java.net.URL;
18import java.text.DateFormat;
19import java.text.SimpleDateFormat;
20import java.util.Arrays;
21import java.util.Date;
22import java.util.LinkedList;
23
24import javax.swing.JLabel;
25import javax.swing.JOptionPane;
26import javax.swing.JPanel;
27import javax.swing.JScrollPane;
28import javax.swing.JTextArea;
29
30import org.openstreetmap.josm.Main;
31import org.openstreetmap.josm.plugins.PluginException;
32import org.openstreetmap.josm.plugins.PluginProxy;
33
34/**
35 * An exception handler that asks the user to send a bug report.
36 *
37 * @author imi
38 */
39public final class BugReportExceptionHandler implements Thread.UncaughtExceptionHandler {
40
41 public void uncaughtException(Thread t, Throwable e) {
42 e.printStackTrace();
43 if (Main.parent != null) {
44 if (e instanceof OutOfMemoryError) {
45 // do not translate the string, as translation may raise an exception
46 JOptionPane.showMessageDialog(Main.parent, "JOSM is out of memory. " +
47 "Strange things may happen.\nPlease restart JOSM with the -Xmx###M option,\n" +
48 "where ### is the the number of MB assigned to JOSM (e.g. 256).\n" +
49 "Currently, " + Runtime.getRuntime().maxMemory()/1024/1024 + " MB are available to JOSM.");
50 return;
51 }
52
53 PluginProxy plugin = null;
54
55 // Check for an explicit problem when calling a plugin function
56 if (e instanceof PluginException)
57 plugin = ((PluginException)e).plugin;
58
59 if (plugin == null)
60 plugin = guessPlugin(e);
61
62 if (plugin != null) {
63 int answer = JOptionPane.showConfirmDialog(
64 Main.parent, tr("An unexpected exception occurred that may have come from the ''{0}'' plugin.",
65 plugin.info.name) + "\n"+ (plugin.info.author != null ?
66 tr("According to the information within the plugin, the author is {0}.",
67 plugin.info.author) : "") + "\n" +
68 tr("Try updating to the newest version of this plugin before reporting a bug.") + "\n" +
69 tr("Should the plugin be disabled?"),
70 tr("Disable plugin"),
71 JOptionPane.YES_NO_OPTION);
72 if (answer == JOptionPane.OK_OPTION) {
73 LinkedList<String> plugins = new LinkedList<String>(Arrays.asList(Main.pref.get("plugins").split(",")));
74 if (plugins.contains(plugin.info.name)) {
75 while (plugins.remove(plugin.info.name)) {}
76 String p = "";
77 for (String s : plugins)
78 p += ","+s;
79 if (p.length() > 0)
80 p = p.substring(1);
81 Main.pref.put("plugins", p);
82 JOptionPane.showMessageDialog(Main.parent,
83 tr("The plugin has been removed from the configuration. Please restart JOSM to unload the plugin."));
84 } else {
85 JOptionPane.showMessageDialog(Main.parent,
86 tr("The plugin could not be removed. Please tell the people you got JOSM from about the problem."));
87 }
88 return;
89 }
90 }
91
92 Object[] options = new String[]{tr("Do nothing"), tr("Report Bug")};
93 int answer = JOptionPane.showOptionDialog(Main.parent, tr("An unexpected exception occurred.\n\n" +
94 "This is always a coding error. If you are running the latest\n" +
95 "version of JOSM, please consider being kind and file a bug report."),
96 tr("Unexpected Exception"), JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE,
97 null, options, options[0]);
98 if (answer == 1) {
99 try {
100 StringWriter stack = new StringWriter();
101 e.printStackTrace(new PrintWriter(stack));
102
103 URL revUrl = Main.class.getResource("/REVISION");
104 StringBuilder sb = new StringBuilder();
105 if (revUrl == null) {
106 sb.append("Development version. Unknown revision.");
107 File f = new File("org/openstreetmap/josm/Main.class");
108 if (!f.exists())
109 f = new File("bin/org/openstreetmap/josm/Main.class");
110 if (!f.exists())
111 f = new File("build/org/openstreetmap/josm/Main.class");
112 if (f.exists()) {
113 DateFormat sdf = SimpleDateFormat.getDateTimeInstance();
114 sb.append("\nMain.class build on "+sdf.format(new Date(f.lastModified())));
115 sb.append("\n");
116 }
117 } else {
118 BufferedReader in = new BufferedReader(new InputStreamReader(revUrl.openStream()));
119 for (String line = in.readLine(); line != null; line = in.readLine()) {
120 sb.append(line);
121 sb.append('\n');
122 }
123 }
124 sb.append("\n"+stack.getBuffer().toString());
125
126 JPanel p = new JPanel(new GridBagLayout());
127 p.add(new JLabel(tr("<html>Please report a ticket at {0}<br>" +
128 "Include your steps to get to the error (as detailed as possible)!<br>" +
129 "Be sure to include the following information:</html>", "http://josm.openstreetmap.de/newticket")), GBC.eol());
130 try {
131 Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(sb.toString()), new ClipboardOwner(){
132 public void lostOwnership(Clipboard clipboard, Transferable contents) {}
133 });
134 p.add(new JLabel(tr("The text has already been copied to your clipboard.")), GBC.eop());
135 }
136 catch (RuntimeException x) {}
137
138 JTextArea info = new JTextArea(sb.toString(), 20, 60);
139 info.setCaretPosition(0);
140 info.setEditable(false);
141 p.add(new JScrollPane(info), GBC.eop());
142
143 JOptionPane.showMessageDialog(Main.parent, p);
144 } catch (Exception e1) {
145 e1.printStackTrace();
146 }
147 }
148 }
149 }
150
151 private PluginProxy guessPlugin(Throwable e) {
152 String name = guessPluginName(e);
153 for (PluginProxy p : Main.plugins)
154 if (p.info.name.equals(name))
155 return p;
156 return null;
157 }
158
159 /**
160 * Analyze the stack of the argument and return a name of a plugin, if
161 * some known problem pattern has been found or <code>null</code>, if
162 * the stack does not contain plugin-code.
163 *
164 * Note: This heuristic is not meant as discrimination against specific
165 * plugins, but only to stop the flood of similar bug reports about plugins.
166 * Of course, plugin writers are free to install their own version of
167 * an exception handler with their email address listed to receive
168 * bug reports ;-).
169 */
170 private String guessPluginName(Throwable e) {
171 for (StackTraceElement element : e.getStackTrace()) {
172 String c = element.getClassName();
173
174 if (c.contains("wmsplugin.") || c.contains(".WMSLayer"))
175 return "wmsplugin";
176 if (c.contains("landsat.") || c.contains(".LandsatLayer"))
177 return "landsat";
178 if (c.contains("livegps."))
179 return "livegps";
180 if (c.contains("mappaint."))
181 return "mappaint";
182 if (c.contains("annotationtester."))
183 return "annotation-tester";
184 if (c.startsWith("UtilsPlugin."))
185 return "UtilsPlugin";
186
187 if (c.startsWith("org.openstreetmap.josm.plugins.")) {
188 String p = c.substring("org.openstreetmap.josm.plugins.".length());
189 if (p.indexOf('.') != -1 && p.matches("[a-z].*")) {
190 return p.substring(0,p.indexOf('.'));
191 }
192 }
193 }
194 return null;
195 }
196}
Note: See TracBrowser for help on using the repository browser.