source: josm/trunk/src/org/openstreetmap/josm/tools/bugreport/BugReportQueue.java@ 11288

Last change on this file since 11288 was 11211, checked in by simon04, 7 years ago

see #13850 - BugReportQueue output original exception to console

Make it consistent with report sent to Trac.

  • Property svn:eol-style set to native
File size: 5.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools.bugreport;
3
4import java.awt.GraphicsEnvironment;
5import java.util.ArrayList;
6import java.util.LinkedList;
7import java.util.concurrent.CopyOnWriteArrayList;
8import java.util.function.BiFunction;
9import java.util.function.Predicate;
10
11import org.openstreetmap.josm.Main;
12import org.openstreetmap.josm.tools.Logging;
13
14/**
15 * This class handles the display of the bug report dialog.
16 * @author Michael Zangl
17 * @since 10819
18 */
19public class BugReportQueue {
20
21 private static final BugReportQueue INSTANCE = new BugReportQueue();
22
23 private final LinkedList<ReportedException> reportsToDisplay = new LinkedList<>();
24 private boolean suppressAllMessages;
25 private final ArrayList<ReportedException> suppressFor = new ArrayList<>();
26 private Thread displayThread;
27 private final BiFunction<ReportedException, Integer, SuppressionMode> bugReportHandler = getBestHandler();
28 private final CopyOnWriteArrayList<Predicate<ReportedException>> handlers = new CopyOnWriteArrayList<>();
29 private int displayedErrors;
30
31 private boolean inReportDialog;
32
33 /**
34 * The suppression mode that should be used after the dialog was closed.
35 */
36 public enum SuppressionMode {
37 /**
38 * Suppress no dialogs.
39 */
40 NONE,
41 /**
42 * Suppress only the ones that are for the same error
43 */
44 SAME,
45 /**
46 * Suppress all report dialogs
47 */
48 ALL
49 }
50
51 /**
52 * Submit a new error to be displayed
53 * @param report The error to display
54 */
55 public synchronized void submit(ReportedException report) {
56 Logging.logWithStackTrace(Logging.LEVEL_ERROR, "Handled by bug report queue", report.getCause());
57 if (suppressAllMessages || suppressFor.stream().anyMatch(report::isSame)) {
58 Main.info("User requested to skip error " + report);
59 } else if (reportsToDisplay.size() > 100 || reportsToDisplay.stream().filter(report::isSame).count() >= 10) {
60 Main.warn("Too many errors. Dropping " + report);
61 } else {
62 reportsToDisplay.add(report);
63 if (displayThread == null) {
64 displayThread = new Thread(new BugReportDisplayRunnable(), "bug-report-display");
65 displayThread.start();
66 }
67 notifyAll();
68 }
69 }
70
71 private class BugReportDisplayRunnable implements Runnable {
72
73 private volatile boolean running = true;
74
75 @Override
76 public void run() {
77 try {
78 while (running) {
79 ReportedException e = getNext();
80 handleDialogResult(e, displayFor(e));
81 }
82 } catch (InterruptedException e) {
83 displayFor(BugReport.intercept(e));
84 }
85 }
86 }
87
88 private synchronized void handleDialogResult(ReportedException e, SuppressionMode suppress) {
89 if (suppress == SuppressionMode.ALL) {
90 suppressAllMessages = true;
91 reportsToDisplay.clear();
92 } else if (suppress == SuppressionMode.SAME) {
93 suppressFor.add(e);
94 reportsToDisplay.removeIf(e::isSame);
95 }
96 displayedErrors++;
97 inReportDialog = false;
98 }
99
100 private synchronized ReportedException getNext() throws InterruptedException {
101 while (reportsToDisplay.isEmpty()) {
102 wait();
103 }
104 inReportDialog = true;
105 return reportsToDisplay.removeFirst();
106 }
107
108 private SuppressionMode displayFor(ReportedException e) {
109 if (handlers.stream().anyMatch(p -> p.test(e))) {
110 Main.trace("Intercepted by handler.");
111 return SuppressionMode.NONE;
112 }
113 return bugReportHandler.apply(e, getDisplayedErrors());
114 }
115
116 private synchronized int getDisplayedErrors() {
117 return displayedErrors;
118 }
119
120 /**
121 * Check if the dialog is shown. Should only be used for e.g. debugging.
122 * @return <code>true</code> if the exception handler is still showing the exception to the user.
123 */
124 public synchronized boolean exceptionHandlingInProgress() {
125 return !reportsToDisplay.isEmpty() || inReportDialog;
126 }
127
128 private static BiFunction<ReportedException, Integer, SuppressionMode> getBestHandler() {
129 if (GraphicsEnvironment.isHeadless()) {
130 return (e, index) -> {
131 e.printStackTrace();
132 return SuppressionMode.NONE;
133 };
134 } else {
135 return BugReportDialog::showFor;
136 }
137 }
138
139 /**
140 * Allows you to peek or even intersect the bug reports.
141 * @param handler The handler. It can return false to stop all further handling of the exception.
142 * @since 10886
143 */
144 public void addBugReportHandler(Predicate<ReportedException> handler) {
145 handlers.add(handler);
146 }
147
148 /**
149 * Gets the global bug report queue
150 * @return The queue
151 * @since 10886
152 */
153 public static BugReportQueue getInstance() {
154 return INSTANCE;
155 }
156}
Note: See TracBrowser for help on using the repository browser.