
/*!
 
 Copyright 2009 Sun Microsystems, Inc.
 
 @author
 jak
 
 @class
 WBExceptionHandlerDelegate
 
 @abstract
 Implements a way to deal with uncaught Obj-C exceptios.
 
 */



#import "WBExceptions.h"



@implementation NSException (WBExceptionExtensions)



/*!
 Print the symbolic stack trace to console.
 */
- (void) logStackTrace;
{
  NSMutableArray* stack = nil;
  
  // Look for stack trace info in the userInfo dictionary.
  NSString* stackString = [[self userInfo] objectForKey: NSStackTraceKey];
  if (stackString != nil) {
    NSArray* stackStrings = [stackString componentsSeparatedByString: @"  "]; // Function addresses are separated by double spaces, not single.
    stack = [NSMutableArray array];
    for (NSString* s in stackStrings) {
      [stack addObject: s];
    }
  }
  
  if (stack == nil) {
    // There was no stack trace info in the userInfo dictionary, so we try to get it from -callStackReturnAddresses.
    NSArray* stackNumbers = [self callStackReturnAddresses];
    if ([stackNumbers count] > 0) {
      stack = [NSMutableArray array];
      for (NSNumber* n in stackNumbers) {
        [stack addObject: [NSString stringWithFormat: @"0x%x", [n intValue]]];
      }
    }
  }
  
  if (stack != nil) {
    // Set up the arguments for the atos tool.
    NSMutableArray* args = [NSMutableArray arrayWithCapacity: 20];
    NSString* pid = [[NSNumber numberWithInt: [[NSProcessInfo processInfo] processIdentifier]] stringValue];
    [args addObject: @"-p"];
    [args addObject: pid];
    [args addObjectsFromArray: stack];
    
    // Set up an NSTask to run the atos tool.
    NSTask* ls = [[NSTask alloc] init];
    [ls setLaunchPath: @"/usr/bin/atos"];
    [ls setArguments: args];
    
    NSLog(@"===================================");
    NSLog(@"=== Exception stack trace begin ===");
    [ls launch];
//    [ls waitUntilExit];

    [ls release];
  }
  else {
    NSLog(@"No stack trace available.");
  }
}



@end



@implementation WBExceptionHandlerDelegate

- (BOOL) exceptionHandler: (NSExceptionHandler*) sender
       shouldLogException: (NSException*) exception
                     mask: (unsigned int) aMask;
{
  NSUserDefaults* sud = [NSUserDefaults standardUserDefaults];
  BOOL reportException = [sud boolForKey: @"ReportException"];
  
  // To enable exception reporting, write the following in terminal:
  // defaults write com.sun.MySQLWorkbench ReportException YES
  // To disable exception reporting, write the following in terminal:
  // defaults write com.sun.MySQLWorkbench ReportException NO
  
  if (reportException) {
    [exception logStackTrace];
    
    int reply = NSRunCriticalAlertPanel(@"An exception has occurred. The stack trace is being written to the log.",
                                        [exception reason],
                                        @"OK",
                                        @"Terminate",
                                        @"");
    
    if (reply == NSAlertAlternateReturn) {
      exit(-1);
    }
  }
  
  return YES;
}



- (BOOL) exceptionHandler: (NSExceptionHandler*) sender
    shouldHandleException: (NSException*) exception
                     mask: (unsigned int) aMask;
{
  return YES;
}



@end


