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

Last change on this file since 7294 was 7082, checked in by Don-vip, 10 years ago

see #8465 - replace Utils.UTF_8 by StandardCharsets.UTF_8, new in Java 7

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