import BR.unicamp.Guarana.*;
import java.lang.reflect.*;

/** Attach to class InvocationTargetException and try to attach to any 
    instances thereof, then print its constructor arguments.  */
public class DetailedException extends MetaObject {
  /** Install an interceptor for InvocationTargetException and start
      the application */
  public static void main(String[] argv) throws Throwable {
    Guarana.reconfigure(InvocationTargetException.class,
			null, new DetailedException());
    /* uncomment the following line:
    your.Application.main(argv);
    /*
       and comment the rest...
    */
    DetailedException.class.getMethod("test", new Class[0])
	.invoke(null, null);
    /* ... until here */
  }

  /** Just throw a Runtime Exception.  */
  public static void test() {
    throw new RuntimeException("test");
  }

  /** Whenever an instance of InvocationTargetException is created,
      try to attach to it */
  public void handle(final Message msg, final Object ob) {
    if (msg instanceof NewObject) {
      Object o = ((NewObject)msg).getObject();
      if (o instanceof InvocationTargetException)
	Guarana.reconfigure(o, null, this);
    }
  }

  /** Intercept constructor invocation and print the constructor
      arguments */
  public Result handle(final Operation op, final Object ob) {
    if (! (ob instanceof InvocationTargetException))
      return null;

    Constructor c = op.getConstructor();
    if (c == null)
      return null;

    Object[] args = op.getArguments();

    System.err.println("Creating InvocationTargetException:");

    if (args.length >= 1 && args[0] instanceof Throwable)
      ((Throwable)args[0]).printStackTrace();

    if (args.length >= 2 && args[1] instanceof String)
       System.err.println("Message: " + args[1]);
    else
       System.err.println("No detail messages supplied for the exception wrapper");

    Guarana.reconfigure(ob, this, null);

    return null;
  }
}
