001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.tools.bugreport; 003 004/** 005 * This class contains utility methods to create and handle a bug report. 006 * <p> 007 * It allows you to configure the format and request to send the bug report. 008 * <p> 009 * It also contains the main entry point for all components to use the bug report system: Call {@link #intercept(Throwable)} to start handling an 010 * exception. 011 * <h1> Handling Exceptions </h1> 012 * In your code, you should add try...catch blocks for any runtime exceptions that might happen. It is fine to catch throwable there. 013 * <p> 014 * You should then add some debug information there. This can be the OSM ids that caused the error, information on the data you were working on 015 * or other local variables. Make sure that no excpetions may occur while computing the values. It is best to send plain local variables to 016 * put(...). Then simply throw the throwable you got from the bug report. The global exception handler will do the rest. 017 * <pre> 018 * int id = ...; 019 * String tag = "..."; 020 * try { 021 * ... your code ... 022 * } catch (Throwable t) { 023 * throw BugReport.intercept(t).put("id", id).put("tag", tag); 024 * } 025 * </pre> 026 * 027 * Instead of re-throwing, you can call {@link ReportedException#warn()}. This will display a warning to the user and allow it to either report 028 * the execption or ignore it. 029 * 030 * @author Michael Zangl 031 * @since 10285 032 */ 033public class BugReport { 034 /** 035 * Create a new bug report 036 * @param e The {@link ReportedException} to use. No more data should be added after creating the report. 037 */ 038 public BugReport(ReportedException e) { 039 // TODO: Use this class to create the bug report. 040 } 041 042 /** 043 * This should be called whenever you want to add more information to a given exception. 044 * @param t The throwable that was thrown. 045 * @return A {@link ReportedException} to which you can add additional information. 046 */ 047 public static ReportedException intercept(Throwable t) { 048 ReportedException e; 049 if (t instanceof ReportedException) { 050 e = (ReportedException) t; 051 } else { 052 e = new ReportedException(t); 053 } 054 e.startSection(getCallingMethod(2)); 055 return e; 056 } 057 058 /** 059 * Find the method that called us. 060 * 061 * @param offset 062 * How many methods to look back in the stack trace. 1 gives the method calling this method, 0 gives you getCallingMethod(). 063 * @return The method name. 064 */ 065 static String getCallingMethod(int offset) { 066 StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); 067 String className = BugReport.class.getName(); 068 for (int i = 0; i < stackTrace.length - offset; i++) { 069 StackTraceElement element = stackTrace[i]; 070 if (className.equals(element.getClassName()) && "getCallingMethod".equals(element.getMethodName())) { 071 StackTraceElement toReturn = stackTrace[i + offset]; 072 return toReturn.getClassName().replaceFirst(".*\\.", "") + '#' + toReturn.getMethodName(); 073 } 074 } 075 return "?"; 076 } 077}