package org.limewire.ui.swing; import java.awt.IllegalComponentStateException; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import org.limewire.service.ErrorService; /** * @author jum * * Implement a generic error handler that catches all errors thrown * by ActionListeners in the AWT event dispatcher thread. */ public class DefaultErrorCatcher { private static volatile boolean storeCaughtBugs = false; private static final List<Throwable> storedBugs = new CopyOnWriteArrayList<Throwable>(); static void install() { System.setProperty("sun.awt.exception.handler", DefaultErrorCatcher.class.getName()); } /** Sets whether or not bugs are captured or reported to ErrorService. */ static void storeCaughtBugs() { storeCaughtBugs = true; } /** Gets all captured bugs & unsets storing. */ static List<Throwable> getAndResetStoredBugs() { storeCaughtBugs = false; List<Throwable> list = new ArrayList<Throwable>(storedBugs); storedBugs.clear(); return list; } public void handle(Throwable ex) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); ex.printStackTrace(pw); pw.flush(); String bug = sw.toString(); if(!isIgnorable(ex, bug)) { if(storeCaughtBugs) { storedBugs.add(ex); } else { ErrorService.error(ex, "Uncaught event-thread error."); } } else { System.err.println("Ignoring error:"); ex.printStackTrace(); } } /** * Determines if the message can be ignored. */ private boolean isIgnorable(Throwable bug, String msg) { // ignore all overflows, // since they'll give us absolutely no debugging information if(bug instanceof StackOverflowError) return true; // no bug? kinda impossible, but shouldn't report. if(msg == null) { return true; } // frickin' repaint manager stinks. if(msg.indexOf("javax.swing.RepaintManager") != -1) return true; if(msg.indexOf("sun.awt.RepaintArea.paint") != -1) return true; // display manager on OSX goes out of whack if(bug instanceof ArrayIndexOutOfBoundsException) { if(msg.indexOf("apple.awt.CWindow.displayChanged") != -1) return true; if(msg.indexOf("javax.swing.plaf.basic.BasicTabbedPaneUI.getTabBounds") != -1) return true; } // system clipboard can be held, preventing us from getting. // throws a RuntimeException through stuff we don't control... if(bug instanceof IllegalStateException) { if(msg.indexOf("cannot open system clipboard") != -1) return true; } // odd component exception if(bug instanceof IllegalComponentStateException) { if(msg.indexOf("component must be showing on the screen to determine its location") != -1) return true; } // various NPEs we can ignore: if(bug instanceof NullPointerException) { if(msg.indexOf("MetalFileChooserUI") != -1) return true; if(msg.indexOf("WindowsFileChooserUI") != -1) return true; if(msg.indexOf("AquaDirectoryModel") != -1) return true; if(msg.indexOf("SizeRequirements.calculateAlignedPositions") != -1) return true; if(msg.indexOf("BasicTextUI.damageRange") != -1) return true; if(msg.indexOf("null pData") != -1) return true; if(msg.indexOf("disposed component") != -1) return true; } // various InternalErrors we can ignore. if(bug instanceof InternalError) { if(msg.indexOf("getGraphics not implemented for this component") != -1) return true; } // if we're not somewhere in the bug, ignore it. // no need for us to debug sun's internal errors. if(msg.indexOf("com.limegroup.gnutella") == -1 && msg.indexOf("org.limewire") == -1) { return true; } StackTraceElement[] stack = bug.getStackTrace(); if(stack != null) { // Internal errors with Swing's FilePane -- we can't do anything about it if(bug instanceof IndexOutOfBoundsException && stack.length > 2) { if(stack[0].getClassName().equals("javax.swing.DefaultRowSorter") && stack[1].getClassName().equals("sun.swing.FilePane$SortableListModel")) { return true; } } if(bug instanceof NullPointerException && stack.length > 2) { if(stack[0].getClassName().equals("javax.swing.JComponent") && stack[1].getClassName().equals("sun.swing.FilePane$2")) { return true; } } } return false; } }