All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bugsplat.BugSplat Maven / Gradle / Ivy

//
// BugSplat integration code for Java applications.
// This class allows a Java application to post
// BugSplat reports on www.bugsplat.com
//
// Copyright 2014 BugSplat, LLC.
//
package com.bugsplat;

import java.awt.*;
import java.io.*;
import java.util.*;
import java.util.zip.*;
import java.text.*;

import com.bugsplat.api.BugSplatClient;
import com.bugsplat.api.BugSplatPostOptions;
import com.bugsplat.api.BugSplatPostResult;
import com.bugsplat.http.BugSplatHttpClientFactory;
import com.bugsplat.http.BugSplatHttpClientFactoryImpl;
import com.bugsplat.util.*;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import java.net.*;

import com.bugsplat.gui.BugSplatDialog;
import com.bugsplat.gui.BugSplatProgress;
import com.bugsplat.gui.BugSplatDetails;

/**
 * BugSplat support for Java applications.
 * 

* See the MyJavaCrasher sample for an implementation example. * */ public class BugSplat implements Runnable { // construct time - required private static String m_strDatabase = ""; private static String m_strAppName = ""; private static String m_strVersion = ""; // additional info - optional private static String m_strKey = ""; private static String m_strNotes = ""; private static String m_strMFA = ""; private final static ArrayList m_additionalFiles = new ArrayList<>(); // dialog data private static String m_strUserName = ""; private static String m_strUserEmail = ""; private static String m_strUserDescription = ""; private static boolean m_bEnableAdditionalFiles = true; // IP address of local host private static String m_strIPAddress = ""; // for server apps private static boolean m_bQuietMode = false; private static String m_strUserFile = ""; private static String m_strStackFile = ""; private static final ArrayList m_requiredFiles = new ArrayList<>(); private static String m_strZipFile = ""; private static boolean m_terminateApplication = false; private static Exception m_ex = null; private static final BugSplatHttpClientFactory httpClientFactory = new BugSplatHttpClientFactoryImpl(); /** * Initialize database, application and version. These are required for * validation when the report is sent to the BugSplat website and for * organizational purposes when navigating the website interactively. */ public static void init( String database, /* database on bugsplat.com */ String application, /* application name */ String version /* version identifier */ ) { m_strDatabase = database; m_strAppName = application; m_strVersion = version; } private static void getIPAddressForLocalHost() { try { // returns the host name/ip address InetAddress inet = InetAddress.getLocalHost(); // get the raw ip only byte[] raw = inet.getAddress(); // java doesn't support unsigned types, // so we have to use some trickery int raw0 = 0xFF & (int) raw[0]; int raw1 = 0xFF & (int) raw[1]; int raw2 = 0xFF & (int) raw[2]; int raw3 = 0xFF & (int) raw[3]; m_strIPAddress = raw0 + "." + raw1 + "." + raw2 + "." + raw3; } catch (Exception e) { System.out.println("Exception in GetIPAddressForLocalHost: " + e); } } private static String getMFAFromException(Exception e) { // first, we need to backtrace... Throwable t = e; while (t.getCause() != null) { t = t.getCause(); } // TODO: MFA should be module, file, address StackTraceElement stack[] = t.getStackTrace(); if (stack.length > 0) { String className = stack[0].getClassName(); String methodName = stack[0].getMethodName(); int line = stack[0].getLineNumber(); // changed from "::" to "." return className + "." + methodName + "(" + line + ")"; } return ""; } private static void setMFA(String MFA) { m_strMFA = MFA; } /** * Set the default value for the user description field * this value can be overwritten by the user in the BugSplat dialog */ public static void setDescription(String description) { m_strUserDescription = description; } /** * Set the default value for the email field * this value can be overwritten by the user in the BugSplat dialog */ public static void setEmail(String email) { m_strUserEmail = email; } /** * Provide an application key that may be used to load different * variations of the support response page. */ public static void setKey(String key) { m_strKey = key; } /** * Provide notes associated with the crash report that can be edited * on the BugSplat website. */ public static void setNotes(String notes) { m_strNotes = notes; } /** * Set the default value for the user field * this value can be overwritten by the user in the BugSplat dialog */ public static void setUser(String user) { m_strUserName = user; } /** * Specify the path to an additional file to be included in the crash report * package sent to the BugSplat website. */ public static void addAdditionalFile(String additionalFile) { m_additionalFiles.add(additionalFile); } /** * Set quiet mode. By default, a progress dialog is displayed as the crash * report is sent to the BugSplat website. Calling this method with a true * argument inhibits the progress dialog. */ public static void setQuietMode(boolean quiet) { m_bQuietMode = quiet; } /** * Get quiet mode behavior set via SetQuietMode(). */ public static boolean getQuietMode() { return m_bQuietMode; } /** * Set application termination behavior. By default, the application is not * terminated after an exception is processed by this class. */ public static void setTerminateApplication(boolean terminate) { m_terminateApplication = terminate; } /** * Get application termination behavior set via SetTerminateApplication(). */ public static boolean getTerminateApplication() { return m_terminateApplication; } /** * Handle a caught exception with BugSplat. The crash report package will be * sent to the BugSplat website. */ public static void handleException(Exception ex) { // save the exception m_ex = ex; // use a ThreadGroup so that we can handle uncaught exceptions ThreadGroup tg = new BugSplatThreadGroup("BugSplatThreadGroup"); BugSplatThread t = new BugSplatThread(tg, new BugSplat()); t.start(); } /** * Used internally to send crash reports. */ public void run() { System.out.println("Entering thread method..."); // check if there is an exception to process if (m_ex == null) { System.out.println("No exception..."); return; } try { // TODO BG only show if m_quietMode true? // show the main crash dialog boolean result = BugSplat.showDialog(); // TODO BG only show if m_quietMode true? // check if user cancelled if (result) { // create the progress dialog BugSplatProgress progress = new BugSplatProgress(BugSplat.getQuietMode()); // send the crash data BugSplat.sendData(m_ex, progress); // show the server response if (progress.TaskComplete != BugSplatProgress.taskSendingReport) { if (!BugSplat.getQuietMode()) { BugSplatDetails details = new BugSplatDetails(progress.ResultString); } } System.out.println("Done."); // release the object to free the underlying memory and window handle progress.dispose(); } if (BugSplat.getTerminateApplication()) { System.exit(1); } } catch (Exception e) { System.out.println("Exception in worker thread."); } // clear the exception m_ex = null; } private static boolean showDialog() { // create the temp files for the stack trace and user info createTempFiles(); // create the main crash dialog BugSplatDialog dialog = new BugSplatDialog( m_strUserName, m_strUserEmail, m_strUserDescription, m_requiredFiles, m_additionalFiles, m_bEnableAdditionalFiles, m_bQuietMode ); // requestFocus(); // get the values from the dialog if (!m_bQuietMode) { m_strUserName = dialog.UserName; m_strUserEmail = dialog.UserEmail; m_strUserDescription = dialog.UserDescription; m_bEnableAdditionalFiles = dialog.m_enableAdditionalFiles; } boolean result = dialog.Result; // release the object to free the underlying memory and window handle dialog.dispose(); return result; } private static void sendData(Exception e, BugSplatProgress progress) { try { getIPAddressForLocalHost(); setMFA(getMFAFromException(e)); createReport(e); collectUserInfo(); createZip(); if (progress.Cancelled) { return; } progress.setTaskComplete(BugSplatProgress.taskCompilingReport); BugSplatPostResult postResult = uploadCrashZip(); if (progress.Cancelled) { return; } progress.setTaskComplete(BugSplatProgress.taskSendingReport); if (!progress.QuietMode && postResult.success) { ShowSupportResponse(postResult.infoUrl); } progress.setVisible(false); } catch (Exception e2) { System.out.println("Exception in SendData: " + e2); } } private static void ShowSupportResponse(String infoUrl) { try { // System.out.println("Launching browser: " + infoURL); if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { Desktop.getDesktop().browse(new URI(infoUrl)); } } catch (Exception e) { System.out.println(e); } } private static BugSplatPostResult uploadCrashZip() throws Exception { CloseableHttpClient client = HttpClients.createDefault(); BugSplatClient report = new BugSplatClient( m_strDatabase, m_strAppName, m_strVersion, httpClientFactory ); BugSplatPostOptions options = new BugSplatPostOptions(); options.additionalFiles = m_additionalFiles; options.description = m_strUserDescription; options.email = m_strUserEmail; options.mfa = m_strMFA; options.notes = m_strNotes; options.key = m_strKey; options.user = m_strUserName; BugSplatPostResult result = report.PostDumpFile(new File(m_strZipFile), options); // TODO BG needed? client.close(); return result; } private static void createTempFiles() { System.out.println("CreateTempFiles..."); try { File temp1 = File.createTempFile("user", ".xml"); m_strUserFile = temp1.toString(); File temp2 = File.createTempFile("stack", ".jdmp"); m_strStackFile = temp2.toString(); m_requiredFiles.clear(); m_requiredFiles.add(m_strUserFile); m_requiredFiles.add(m_strStackFile); } catch (IllegalArgumentException iae) { System.out.println("IllegalArgumentException in CreateTempFiles: " + iae); } catch (IOException ioe) { System.out.println("IOException in CreateTempFiles: " + ioe); } catch (SecurityException se) { System.out.println("SecurityException in CreateTempFiles: " + se); } } private static void collectUserInfo() { System.out.println("CollectUserInfo..."); DateFormat dateFormat1 = new SimpleDateFormat("yy-MM-dd"); DateFormat dateFormat2 = new SimpleDateFormat("HH:mm:ss"); String datetime = dateFormat1.format(new Date()) + " " + dateFormat2.format(new Date()); // NOTE: we need to wrap most elements in CDATA sections // characters such as < and > will cause errors when user.xml is read // these can come from user input on the crash dialog or from the MFA try { // open the temp file File temp = new File(m_strUserFile); // Write to temp file BufferedWriter out = new BufferedWriter(new FileWriter(temp)); // no DOM or SAX needed! out.write("\n"); out.write(" "); out.write("1.0"); out.write("\n"); out.write(" \n"); // no CDATA - this is validated against illegal chars when they sign up out.write(" "); out.write(m_strDatabase); out.write("\n"); out.write(" "); out.write(""); out.write("\n"); out.write(" "); out.write(""); out.write("\n"); out.write(" "); out.write(""); out.write("\n"); out.write(" \n"); out.write(" \n"); out.write(" \n"); out.write(" "); out.write(""); out.write("\n"); out.write(" "); out.write(""); out.write("\n"); out.write(" "); out.write(""); out.write("\n"); out.write(" \n"); // no CDATA - we format and write this one out.write(" "); out.write(datetime); out.write("\n"); out.write(" "); out.write(""); out.write("\n"); out.write(" "); out.write(""); out.write("\n"); out.write(" "); out.write("\n"); out.write(" "); out.write("\n"); out.write(" \n"); out.write("\n"); out.flush(); out.close(); } catch (IOException ioe) { System.out.println("IOException in CollectionUserInfo: " + ioe); } catch (Exception e) { System.out.println("Exception in CollectionUserInfo: " + e); } } private static void createReport(Exception ex) { System.out.println("CreateReport..."); try { // Create temp file. File temp = new File(m_strStackFile); // Write to temp file BufferedWriter out = new BufferedWriter(new FileWriter(temp)); // first, we need to backtrace... Throwable t = ex; while (t.getCause() != null) { t = t.getCause(); } StackTraceElement stack[] = t.getStackTrace(); // stack[0] contains the method that created the exception. // stack[stack.length-1] contains the oldest method call. // Enumerate each stack element. for (int i = 0; i < stack.length; i++) { String filename = stack[i].getFileName(); String className = stack[i].getClassName(); String methodName = stack[i].getMethodName(); String fileName = stack[i].getFileName(); boolean isNativeMethod = stack[i].isNativeMethod(); int lineNumber = stack[i].getLineNumber(); // TODO: should we use toString? // out.write(className + "::" + methodName + "(" + lineNumber + ")\n"); String msg = className + "." + methodName; // write the header information on the first pass through the loop if (i == 0) { out.write("\n"); out.write(" \n"); out.write(" \n"); out.write(" \n"); // stack key out.write(" \n"); // not sure how to handle the Source info, so for now I'm just sticking // it in the explanation field out.write(" \n"); out.write(" " + fileName + "\n"); out.write(" " + lineNumber + "\n"); out.write(" \n"); out.write(" \n"); out.write(" \n"); out.write(" \n"); out.write(" \n"); } // write this frame of the stack out.write(" \n"); out.write(" \n"); out.write(" \n"); out.write(" \n"); out.write(" " + fileName + "\n"); out.write(" " + lineNumber + "\n"); out.write(" \n"); } // write the xml epilogue and close the stream out.write(" \n"); out.write(" \n"); out.write(" \n"); out.write("\n"); out.close(); // System.out.println("Stack trace: " + temp.toString()); } catch (IOException ioe) { System.out.println("IOException in CreateReport: " + ioe); } catch (Exception e) { System.out.println("Exception in CreateReport: " + e); } } // http://www.devshed.com/c/a/Java/Zip-Meets-Java/1/ private static void createZip() { System.out.println("CreateZip..."); try { DateFormat dateFormat1 = new SimpleDateFormat("MMddyy"); DateFormat dateFormat2 = new SimpleDateFormat("HHmmss"); String date = dateFormat1.format(new Date()); String time = dateFormat2.format(new Date()); String tmpDirName = System.getProperty("java.io.tmpdir"); if (!tmpDirName.endsWith(File.separator)) { tmpDirName = tmpDirName + File.separator; } String zipFileName = tmpDirName + m_strDatabase + "Crash_" + date + "_" + time + ".zip"; byte[] buffer = new byte[18024]; ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFileName)); m_strZipFile = zipFileName; // // stack file // System.out.println("Stackfile: " + m_strStackFile); // remove the path String entry = new File(m_strStackFile).getName(); FileInputStream in = new FileInputStream(m_strStackFile); out.putNextEntry(new ZipEntry(entry)); int len; while ((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); } // close the current entry out.closeEntry(); // close the current file input stream in.close(); // delete it File temp1 = new File(m_strStackFile); temp1.delete(); // // user file // System.out.println("Userfile: " + m_strUserFile); // remove the path entry = new File(m_strUserFile).getName(); FileInputStream in2 = new FileInputStream(m_strUserFile); out.putNextEntry(new ZipEntry(entry)); while ((len = in2.read(buffer)) > 0) { out.write(buffer, 0, len); } // close the current entry out.closeEntry(); // close the current file input stream in2.close(); // delete it File temp2 = new File(m_strUserFile); temp2.delete(); // // additional files // if (m_bEnableAdditionalFiles) { for (String additionalFile : m_additionalFiles) { System.out.println("Userfile: " + additionalFile); // remove the path entry = new File(additionalFile).getName(); FileInputStream in3 = new FileInputStream(additionalFile); out.putNextEntry(new ZipEntry(entry)); while ((len = in3.read(buffer)) > 0) { out.write(buffer, 0, len); } // close the current entry out.closeEntry(); // close the current file input stream in3.close(); } } // close the ZipOutPutStream out.close(); System.out.println("Zipfile: " + m_strZipFile); } catch (IllegalArgumentException iae) { System.out.println("IllegalArgumentException in CreateZip: " + iae); } catch (FileNotFoundException fnfe) { System.out.println("FileNotFoundException in CreateZip: " + fnfe); } catch (IOException ioe) { System.out.println("IOException in CreateZip: " + ioe); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy