import java.dyn.*;
import java.lang.reflect.*;

public class Hello {
  private final static int MAX=100000000;

  public static void main(String... av) throws Throwable {
      {
	long before = System.currentTimeMillis();
      	for(int i=0;i<MAX;i++) {
      	  InvokeDynamic.hail("foo");
      	}   
      	long after = System.currentTimeMillis();
      	System.out.println("Duration invokedynamic: "+(after-before));
      }
      {
      	Method m = Hello.class.getMethod("greeter",String.class);
     	long before = System.currentTimeMillis();
      	for(int i=0;i<MAX;i++) {
            m.invoke(null,"foo");
      	}
      	long after = System.currentTimeMillis();
      	System.out.println("Duration reflection: "+(after-before));
      }
  }

  public static void greeter(String x) { 
}
  
  //es wird ein MethodHandle fuer die methode benoetigt, dies kann man mit MethodHandles.lookup() bekommen
  static MethodHandle greeter = MethodHandles.lookup().findStatic(Hello.class, "greeter",
                                                                  MethodType.methodType(void.class, String.class));

  //damit dynamische aufrufe moeglich sind, muss eine bootstrapmethode definiert werden
  //diese Methode muss dem Linkage objekt bekannt gemacht werden, damit die Methode fuer die Aufloesung aufgerufen werden kann
  static { Linkage.registerBootstrapMethod("bootstrapDynamic"); }

  //die bootstrap methode uebernimmt den caller, den namen fuer die methode und den datentyp der methode und gibt eine Aufrufstelle in form eines CallSite Objekts zurueck
  private static CallSite bootstrapDynamic(Class caller, String name, MethodType type) {
    assert(type.parameterCount() == 1 && name == "hail");
    //hier wird das methodhandle konvertiert, dass es dem datentyp der methode entspricht, dazu wird wieder methodhandles verwendet
    MethodHandle target = MethodHandles.convertArguments(greeter, type);
    //es wird eine aufrufstelle erzeugt die den caller, den methoden namen und den methodentyp kennt
    CallSite site = new CallSite(caller, name, type);
    //als ziel der aufrufstelle wird das methodenhandle, das ebn bestimmt wurde angegeben.
    site.setTarget(target);
    //ie aufrufstelle wird zurueckgegeben
    return site;
  }
}
