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

Last change on this file since 6897 was 6897, checked in by stoecker, 10 years ago

see #9778 - use TLS for JOSM website access

  • Property svn:eol-style set to native
File size: 10.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Component;
7import java.awt.GridBagLayout;
8import java.io.ByteArrayOutputStream;
9import java.io.IOException;
10import java.io.PrintWriter;
11import java.io.StringWriter;
12import java.net.URL;
13import java.nio.ByteBuffer;
14import java.util.zip.GZIPOutputStream;
15
16import javax.swing.JCheckBox;
17import javax.swing.JLabel;
18import javax.swing.JOptionPane;
19import javax.swing.JPanel;
20import javax.swing.JScrollPane;
21import javax.swing.SwingUtilities;
22
23import org.openstreetmap.josm.Main;
24import org.openstreetmap.josm.actions.ShowStatusReportAction;
25import org.openstreetmap.josm.gui.ExtendedDialog;
26import org.openstreetmap.josm.gui.preferences.plugin.PluginPreference;
27import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
28import org.openstreetmap.josm.gui.widgets.JosmTextArea;
29import org.openstreetmap.josm.gui.widgets.UrlLabel;
30import org.openstreetmap.josm.plugins.PluginDownloadTask;
31import org.openstreetmap.josm.plugins.PluginHandler;
32
33/**
34 * An exception handler that asks the user to send a bug report.
35 *
36 * @author imi
37 */
38public final class BugReportExceptionHandler implements Thread.UncaughtExceptionHandler {
39
40 private static boolean handlingInProgress = false;
41 private static BugReporterThread bugReporterThread = null;
42 private static int exceptionCounter = 0;
43 private static boolean suppressExceptionDialogs = false;
44
45 private static class BugReporterThread extends Thread {
46
47 final Throwable e;
48
49 public BugReporterThread(Throwable t) {
50 super("Bug Reporter");
51 this.e = t;
52 }
53
54 @Override
55 public void run() {
56 // Give the user a chance to deactivate the plugin which threw the exception (if it was thrown from a plugin)
57 final PluginDownloadTask pluginDownloadTask = PluginHandler.updateOrdisablePluginAfterException(e);
58
59 SwingUtilities.invokeLater(new Runnable() {
60 @Override
61 public void run() {
62 // Then ask for submitting a bug report, for exceptions thrown from a plugin too, unless updated to a new version
63 if (pluginDownloadTask == null) {
64 ExtendedDialog ed = new ExtendedDialog(Main.parent, tr("Unexpected Exception"), new String[] {tr("Do nothing"), tr("Report Bug")});
65 ed.setIcon(JOptionPane.ERROR_MESSAGE);
66 JPanel pnl = new JPanel(new GridBagLayout());
67 pnl.add(new JLabel(
68 "<html>" + tr("An unexpected exception occurred.<br>" +
69 "This is always a coding error. If you are running the latest<br>" +
70 "version of JOSM, please consider being kind and file a bug report."
71 )
72 + "</html>"), GBC.eol());
73 JCheckBox cbSuppress = null;
74 if (exceptionCounter > 1) {
75 cbSuppress = new JCheckBox(tr("Suppress further error dialogs for this session."));
76 pnl.add(cbSuppress, GBC.eol());
77 }
78 ed.setContent(pnl);
79 ed.showDialog();
80 if (cbSuppress != null && cbSuppress.isSelected()) {
81 suppressExceptionDialogs = true;
82 }
83 if (ed.getValue() != 2) return;
84 askForBugReport(e);
85 } else {
86 // Ask for restart to install new plugin
87 PluginPreference.notifyDownloadResults(Main.parent, pluginDownloadTask);
88 }
89 }
90 });
91 }
92 }
93
94 @Override
95 public void uncaughtException(Thread t, Throwable e) {
96 handleException(e);
97 }
98
99 //http://stuffthathappens.com/blog/2007/10/15/one-more-note-on-uncaught-exception-handlers/
100 /**
101 * Handles the given throwable object
102 * @param t The throwable object
103 */
104 public void handle(Throwable t) {
105 handleException(t);
106 }
107
108 /**
109 * Handles the given exception
110 * @param e the exception
111 */
112 public static void handleException(final Throwable e) {
113 if (handlingInProgress || suppressExceptionDialogs)
114 return; // we do not handle secondary exceptions, this gets too messy
115 if (bugReporterThread != null && bugReporterThread.isAlive())
116 return;
117 handlingInProgress = true;
118 exceptionCounter++;
119 try {
120 Main.error(e);
121 if (Main.parent != null) {
122 if (e instanceof OutOfMemoryError) {
123 // do not translate the string, as translation may raise an exception
124 JOptionPane.showMessageDialog(Main.parent, "JOSM is out of memory. " +
125 "Strange things may happen.\nPlease restart JOSM with the -Xmx###M option,\n" +
126 "where ### is the number of MB assigned to JOSM (e.g. 256).\n" +
127 "Currently, " + Runtime.getRuntime().maxMemory()/1024/1024 + " MB are available to JOSM.",
128 "Error",
129 JOptionPane.ERROR_MESSAGE
130 );
131 return;
132 }
133
134 bugReporterThread = new BugReporterThread(e);
135 bugReporterThread.start();
136 }
137 } finally {
138 handlingInProgress = false;
139 }
140 }
141
142 private static void askForBugReport(final Throwable e) {
143 try {
144 final int maxlen = 6000;
145 StringWriter stack = new StringWriter();
146 e.printStackTrace(new PrintWriter(stack));
147
148 String text = ShowStatusReportAction.getReportHeader() + stack.getBuffer().toString();
149 String urltext = text.replaceAll("\r","");
150 if (urltext.length() > maxlen) {
151 urltext = urltext.substring(0,maxlen);
152 int idx = urltext.lastIndexOf('\n');
153 // cut whole line when not loosing too much
154 if (maxlen-idx < 200) {
155 urltext = urltext.substring(0,idx+1);
156 }
157 urltext += "...<snip>...\n";
158 }
159
160 JPanel p = new JPanel(new GridBagLayout());
161 p.add(new JMultilineLabel(
162 tr("You have encountered an error in JOSM. Before you file a bug report " +
163 "make sure you have updated to the latest version of JOSM here:")), GBC.eol());
164 p.add(new UrlLabel(Main.getJOSMWebsite(),2), GBC.eop().insets(8,0,0,0));
165 p.add(new JMultilineLabel(
166 tr("You should also update your plugins. If neither of those help please " +
167 "file a bug report in our bugtracker using this link:")), GBC.eol());
168 p.add(getBugReportUrlLabel(urltext), GBC.eop().insets(8,0,0,0));
169 p.add(new JMultilineLabel(
170 tr("There the error information provided below should already be " +
171 "filled in for you. Please include information on how to reproduce " +
172 "the error and try to supply as much detail as possible.")), GBC.eop());
173 p.add(new JMultilineLabel(
174 tr("Alternatively, if that does not work you can manually fill in the information " +
175 "below at this URL:")), GBC.eol());
176 p.add(new UrlLabel(Main.getJOSMWebsite()+"/newticket",2), GBC.eop().insets(8,0,0,0));
177 if (Utils.copyToClipboard(text)) {
178 p.add(new JLabel(tr("(The text has already been copied to your clipboard.)")), GBC.eop());
179 }
180
181 JosmTextArea info = new JosmTextArea(text, 18, 60);
182 info.setCaretPosition(0);
183 info.setEditable(false);
184 p.add(new JScrollPane(info), GBC.eop());
185
186 for (Component c: p.getComponents()) {
187 if (c instanceof JMultilineLabel) {
188 ((JMultilineLabel)c).setMaxWidth(400);
189 }
190 }
191
192 JOptionPane.showMessageDialog(Main.parent, p, tr("You have encountered a bug in JOSM"), JOptionPane.ERROR_MESSAGE);
193 } catch (Exception e1) {
194 Main.error(e1);
195 }
196 }
197
198 /**
199 * Determines if an exception is currently being handled
200 * @return {@code true} if an exception is currently being handled, {@code false} otherwise
201 */
202 public static boolean exceptionHandlingInProgress() {
203 return handlingInProgress;
204 }
205
206 /**
207 * Replies the URL to create a JOSM bug report with the given debug text
208 * @param debugText The debug text to provide us
209 * @return The URL to create a JOSM bug report with the given debug text
210 * @since 5849
211 */
212 public static URL getBugReportUrl(String debugText) {
213 try {
214 ByteArrayOutputStream out = new ByteArrayOutputStream();
215 GZIPOutputStream gzip = new GZIPOutputStream(out);
216 gzip.write(debugText.getBytes(Utils.UTF_8));
217 Utils.close(gzip);
218
219 return new URL(Main.getJOSMWebsite()+"/josmticket?" +
220 "gdata="+Base64.encode(ByteBuffer.wrap(out.toByteArray()), true));
221 } catch (IOException e) {
222 Main.error(e);
223 return null;
224 }
225 }
226
227 /**
228 * Replies the URL label to create a JOSM bug report with the given debug text
229 * @param debugText The debug text to provide us
230 * @return The URL label to create a JOSM bug report with the given debug text
231 * @since 5849
232 */
233 public static final UrlLabel getBugReportUrlLabel(String debugText) {
234 URL url = getBugReportUrl(debugText);
235 if (url != null) {
236 return new UrlLabel(url.toString(), Main.getJOSMWebsite()+"/josmticket?...", 2);
237 }
238 return null;
239 }
240}
Note: See TracBrowser for help on using the repository browser.