import com.sun.jdi.*; 
import com.sun.jdi.connect.*; 
import com.sun.jdi.event.*; 
import com.sun.jdi.request.BreakpointRequest; 

import java.util.List; 
import java.util.Map; 

public class Debugger {
	public static void main(String[] args) throws Exception { 
		System.out.println("Java: " + System.getProperty("java.version")); 
		AttachingConnector connector = getConnector(); 

		Map<String, Connector.Argument> cArgs = connector.defaultArguments(); 
		cArgs.get("port").setValue("" + 7777); 
		cArgs.get("hostname").setValue("localhost"); 

		VirtualMachine vm = connector.attach(cArgs); 
		vm.resume(); 

		considerReferenceTypes(vm); 
		listen(vm); 
		System.out.println("Done..."); 
	} 

	private static AttachingConnector getConnector() { 
		VirtualMachineManager vmm = Bootstrap.virtualMachineManager(); 
		AttachingConnector connector = null; 
		for (AttachingConnector c : vmm.attachingConnectors()) { 
			if (c.name().equals("com.sun.jdi.SocketAttach")) { 
				connector = c; 
				break; 
			} 
		} 
		if (connector == null) throw new RuntimeException("no connector"); 
		return connector; 
	} 

	private static void listen(VirtualMachine vm) throws Exception { 
		EventQueue eventQueue = vm.eventQueue(); 
		System.out.println("Listening for events..."); 
		while (true) { 
			EventSet es = eventQueue.remove(); 
			if (es == null) break; 
			handle(es); 
		} 
	} 

	private static void handle(EventSet eventSet) throws Exception { 
		for (Event event : eventSet) { 
			if (event instanceof BreakpointEvent) { 
				Thread.sleep(100); 
				System.out.println("Breakpoint at " + ((BreakpointEvent) event).location()); 
				ThreadReference thread = ((BreakpointEvent) event).thread(); 
				List<StackFrame> frames = thread.frames(); 
				thread.popFrames(frames.get(0)); 
			} 
		} 
		eventSet.resume(); 
	} 

	private static void considerReferenceTypes(VirtualMachine vm) throws AbsentInformationException { 
		for (ReferenceType t : vm.allClasses()) considerReferenceType(t); 
	} 

	private static void considerReferenceType(ReferenceType t) throws AbsentInformationException { 
		if (!t.name().contains("Script$Recompilation")) return; 
		for (Location l : t.allLineLocations()) { 
			if (!l.method().name().contains("target")) continue; // see Debugee.java 
			if (l.lineNumber() < 3) continue; // see Debugee.java 
			BreakpointRequest breakpointRequest = t.virtualMachine().eventRequestManager().createBreakpointRequest(l); 
			System.out.println("Setting breakpoint for " + l); 
			breakpointRequest.enable(); 
			break; 
		} 
	} 
}
