BowlerKernel
IssueReportingExceptionHandler.java
Go to the documentation of this file.
1 package com.neuronrobotics.bowlerstudio;
2 
3 import java.io.IOException;
4 import java.lang.Thread.UncaughtExceptionHandler;
5 import java.util.ArrayList;
6 import java.util.HashMap;
7 import java.util.List;
8 import java.util.Optional;
9 
10 import org.kohsuke.github.GHIssue;
11 import org.kohsuke.github.GHIssueBuilder;
12 import org.kohsuke.github.GHIssueComment;
13 import org.kohsuke.github.GHIssueState;
14 import org.kohsuke.github.GHRepository;
15 import org.kohsuke.github.GHUser;
16 import org.kohsuke.github.GitHub;
17 
18 import com.neuronrobotics.bowlerkernel.BowlerKernelBuildInfo;
19 import com.neuronrobotics.bowlerstudio.assets.StudioBuildInfo;
20 import com.neuronrobotics.bowlerstudio.scripting.PasswordManager;
21 import com.neuronrobotics.javacad.JavaCadBuildInfo;
22 import com.neuronrobotics.sdk.config.SDKBuildInfo;
23 import com.neuronrobotics.video.OSUtil;
24 
25 import javafx.application.Platform;
26 import javafx.scene.control.Alert;
27 import javafx.scene.control.Alert.AlertType;
28 import javafx.scene.control.ButtonType;
29 
30 public class IssueReportingExceptionHandler implements UncaughtExceptionHandler {
31  private static int timerErrorCount = 0;
32  String stacktraceFromHandlerInstantiation;
33  private int fxExceptionCount;
34  private static boolean processing = false;
35  private static HashMap<Throwable, String> exceptionQueue = new HashMap<Throwable, String>();
36  private static boolean reportIssues = false;
37 
38  private static HashMap<String, Integer> exceptionCounter = new HashMap<String, Integer>();
39 
41  stacktraceFromHandlerInstantiation = org.apache.commons.lang.exception.ExceptionUtils
42  .getStackTrace(new Exception());
43  }
44 
45  @Override
46  public void uncaughtException(Thread t, Throwable e) {
47  if (e == null) {
48  except(new Exception("A null exception was thrown"));
49  }
50 
51  except(e);
52 
53  }
54 
55  public static void runLater(Runnable r) {
56  runLater(r, new Exception("UI Thread Exception here!"));
57  }
58 
59  public static void runLater(Runnable r, Throwable ex) {
60  Platform.runLater(() -> {
61  try {
62  r.run();
63  } catch (Throwable t) {
64  t.printStackTrace();
65  ex.printStackTrace();
66  }
67 
68  });
69  }
70 
71  public void except(Throwable e, String stacktraceFromCatch) {
72  System.out.println(stacktraceFromCatch);
73  new Thread(() -> {
74  String stacktrace = org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(e);
75  StackTraceElement[] element = e.getStackTrace();
76  String source = getTitle(element);
77 
78  if (exceptionCounter.get(source) == null) {
79  exceptionCounter.put(source, 0);
80  }
81  exceptionCounter.put(source, exceptionCounter.get(source) + 1);
82  if (exceptionCounter.get(source) > 1) {
83 // Alert alert = new Alert(AlertType.CONFIRMATION);
84 // alert.setTitle("IRRECOVERABLE FAULT");
85 // alert.setHeaderText("Its just gunna crash, sorry...");
86 // alert.setContentText("I can wait till you hit yes, buts its basically done...");
87 // Optional<ButtonType> result = alert.showAndWait();
88 // System.exit(-1);
89  return;// maybe just swallowing after 5 reports is good enough??
90  }
91  if (element != null)
92  if (element.length > 0) {
93  if (element[0].getClassName() != null)
94  if (element[0].getClassName().contains("com.sun.scenario.animation.AbstractMasterTimer")) {
95  if (timerErrorCount++ > 5) {
96  try {
97  Thread.sleep(5000);
98  } catch (InterruptedException e1) {
99  // TODO Auto-generated catch block
100  e1.printStackTrace();
101  } // wait for the Issue to be reported
102  System.exit(-5);
103  }
104  return;
105  } else if (element[0].getClassName().contains("javafx.embed.swing.SwingNode")) {
106  if (timerErrorCount++ > 5) {
107  try {
108  Thread.sleep(5000);
109  } catch (InterruptedException e1) {
110  // TODO Auto-generated catch block
111  e1.printStackTrace();
112  } // wait for the Issue to be reported
113  System.exit(-5);
114  }
115  return;
116  } else if (checkIgnoreExceptions(e)) {
117  e.printStackTrace();
118  return;
119  } else if (java.lang.OutOfMemoryError.class.isInstance(e)
120  || stacktrace.contains("java.lang.OutOfMemoryError")) {
121  e.printStackTrace();
122  System.exit(-1);
123  }
124  }
125 
126  String javaVersion = System.getProperty("java.version");
127  String javafxVersion = System.getProperty("javafx.version");
128  String body = "Auto Reported Issue \r\n" + "BowlerStudio Build " + StudioBuildInfo.getVersion() + "\n"
129  + "BowlerKernel " + BowlerKernelBuildInfo.getVersion() + "\n" + "JavaCad Version: "
130  + JavaCadBuildInfo.getVersion() + "\n" + "Java-Bowler Version: " + SDKBuildInfo.getVersion() + "\n"
131  + "Java Version: " + javaVersion + "\n" + "JavaFX Version: " + javafxVersion + "\n" + "\nOS = "
132  + OSUtil.getOsName() + " " + OSUtil.getOsArch() + " " + (OSUtil.is64Bit() ? "x64" : "x86") + "\r\n"
133  + "```\n" + stacktrace + "\n```" + "\n\nCaught and reported at: \n" + "```\n" + stacktraceFromCatch
134  + "\n```\n" + "\nIssueReportingExceptionHandler Created at:\n" + "\n```\n"
135  + stacktraceFromHandlerInstantiation + "\n```\n";
136  System.err.println(body);
137  System.err.println("\r\n\r\nBug Reported!\r\n\r\n");
138  System.out.println(body);
139  System.out.println("\r\n\r\nBug Reported!\r\n\r\n");
140  GitHub github = PasswordManager.getGithub();
141 
142  if (github == null || github.isAnonymous())
143  return;
144  processing = true;
145  if (reportIssues) {
146  runReport(element, body, github);
147  return;
148  }
149  Platform.runLater(() -> {
150  Alert alert = new Alert(AlertType.CONFIRMATION);
151  alert.setTitle("An Error occoured");
152  alert.setHeaderText("Would it be ok if I report this issue back to Kevin so he can fix it?");
153  alert.setContentText("Are you ok with this?");
154  Optional<ButtonType> result = alert.showAndWait();
155  if (result.get() == ButtonType.OK) {
156  reportIssues = true;
157  runReport(element, body, github);
158  } else {
159  processing = false;
160  }
161  });
162 
163  }).start();
164  }
165 
166  private void runReport(StackTraceElement[] element, String body, GitHub github) {
167  new Thread(() -> {
168  try {
169  GHRepository repo = github.getOrganization("CommonWealthRobotics").getRepository("BowlerStudio");
170  List<GHIssue> issues = repo.getIssues(GHIssueState.ALL);
171  String source = getTitle(element);
172 
173  for (GHIssue i : issues) {
174  System.err.println("Issues are :" + i.getTitle());
175  if (i.getTitle().contains(source)) {
176  List<GHIssueComment> comments = i.getComments();
177  // Check to see if i created this issue
178  boolean metoo = false;
179  try {
180 
181  GHUser user = i.getUser();
182  if (user != null) {
183  String name = user.getName();
184  if (name != null) {
185  String username = PasswordManager.getUsername();
186  if (username != null) {
187  metoo = name.contentEquals(username);
188  for (GHIssueComment comment : comments) {
189  // check to see if i commented on this issue
190  if (comment.getUser().getName().contentEquals(username)) {
191  metoo = true;
192  }
193  }
194  }
195  }
196  }
197  } catch (Throwable t) {
198 
199  }
200  // If i havent commented yet, comment that i had this issue too.
201  if (!metoo)
202  i.comment(body);
203  if (i.getState() == GHIssueState.CLOSED) {
204  try {
205  i.reopen();
206  } catch (Throwable t) {
207  }
208  }
209  BowlerKernel.upenURL(i.getHtmlUrl().toURI());
210  return;
211  }
212 
213  }
214 
215  GHIssue i = repo.createIssue("Build " + StudioBuildInfo.getVersion() + " " + source).body(body)
216  .label("BUG").label("AUTO_REPORTED").assignee("madhephaestus").create();
217  BowlerKernel.upenURL(i.getHtmlUrl().toURI());
218 
219  } catch (Throwable e) {
220  // TODO Auto-generated catch block
221  e.printStackTrace();
222  }
223  processing = false;
224  if (!exceptionQueue.isEmpty()) {
225  Throwable exception = (Throwable) exceptionQueue.keySet().toArray()[0];
226  String source = exceptionQueue.remove(exception);
227  except(exception, source);
228  }
229  }).start();
230 
231  }
232 
233  public void except(Throwable t) {
234  String stacktraceFromCatch = org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(new Exception());
235  StackTraceElement[] element = t.getStackTrace();
236 
237  String className = element[0].getClassName();
238  if (checkIgnoreExceptions(t)) {
239  t.printStackTrace();
240  return;
241  }
242  if (Platform.isFxApplicationThread()) {
243 
244  System.err.println("Exception in Javafx thread! \n"
245  + org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(t));
246  fxExceptionCount++;
247  if (fxExceptionCount > 10) {
248  System.err.println(stacktraceFromCatch);
249  t.printStackTrace();
250  System.exit(-5);
251  }
252  throw new RuntimeException(t);
253  }
254 
255  if (processing) {
256  exceptionQueue.put(t, stacktraceFromCatch);
257  return;
258  }
259 
260  except(t, stacktraceFromCatch);
261  }
262 
263  private boolean checkIgnoreExceptions(Throwable t) {
264  try {
265  return t.getStackTrace()[0].getClassName().contains("DropHandler") || t.getMessage().contains("Key already associated with a running event loop");
266  }catch(Throwable tf) {
267  return false;
268  }
269  }
270 
271  public static String getTitle(Throwable element) {
272  return getTitle(element.getStackTrace());
273  }
274 
275  public static String getTitle(StackTraceElement[] element) {
276  if (element.length == 0)
277  return "No exception trace found";
278  return element[0].getClassName() + " at line " + element[0].getLineNumber();
279  }
280 }
void runReport(StackTraceElement[] element, String body, GitHub github)