1 19 20 package org.netbeans.api.debugger.jpda; 21 22 import java.net.MalformedURLException ; 23 import java.util.HashMap ; 24 import java.util.Map ; 25 import org.netbeans.api.debugger.*; 26 27 import java.io.*; 28 import java.util.*; 29 import java.net.URLClassLoader ; 30 import java.net.URL ; 31 import java.beans.PropertyChangeEvent ; 32 import java.text.DateFormat ; 33 import java.text.SimpleDateFormat ; 34 35 import com.sun.jdi.connect.*; 36 import com.sun.jdi.VirtualMachineManager; 37 import com.sun.jdi.Bootstrap; 38 41 46 public class JPDASupport implements DebuggerManagerListener { 47 48 private static final boolean verbose = false; 49 private static final DateFormat df = new SimpleDateFormat ("kk:mm:ss.SSS"); 50 private static DebuggerManager dm = DebuggerManager.getDebuggerManager (); 51 52 private JPDADebugger jpdaDebugger; 53 private DebuggerEngine debuggerEngine; 54 55 56 private Object [] debuggerStartLock = new Object [1]; 57 private Object [] stepLock = new Object [1]; 58 59 private Object STATE_LOCK = new Object (); 60 61 62 private JPDASupport (JPDADebugger jpdaDebugger) { 63 this.jpdaDebugger = jpdaDebugger; 64 jpdaDebugger.addPropertyChangeListener (this); 65 DebuggerEngine[] de = dm.getDebuggerEngines (); 66 int i, k = de.length; 67 for (i = 0; i < k; i++) 68 if (de [i].lookupFirst (null, JPDADebugger.class) == jpdaDebugger) { 69 debuggerEngine = de [i]; 70 break; 71 } 72 } 73 74 75 77 121 public static JPDASupport attach (String mainClass) throws IOException, 122 DebuggerStartException { 123 Process process = launchVM (mainClass, "", true); 124 String line = readLine (process.getInputStream ()); 125 int port = Integer.parseInt (line.substring (line.lastIndexOf (':') + 1).trim ()); 126 ProcessIO pio = new ProcessIO (process); 127 pio.go (); 128 129 VirtualMachineManager vmm = Bootstrap.virtualMachineManager(); 130 List aconnectors = vmm.attachingConnectors(); 131 AttachingConnector connector = null; 132 for (Iterator i = aconnectors.iterator(); i.hasNext();) { 133 AttachingConnector ac = (AttachingConnector) i.next(); 134 Transport t = ac.transport (); 135 if (t != null && t.name().equals("dt_socket")) { 136 connector = ac; 137 break; 138 } 139 } 140 if (connector == null) 141 throw new RuntimeException 142 ("No attaching socket connector available"); 143 144 JPDADebugger jpdaDebugger = JPDADebugger.attach ( 145 "localhost", 146 port, 147 createServices () 148 ); 149 return new JPDASupport (jpdaDebugger); 150 } 151 152 153 155 public void doContinue () { 156 if (jpdaDebugger.getState () != JPDADebugger.STATE_STOPPED) 157 throw new IllegalStateException (); 158 debuggerEngine.getActionsManager ().doAction 159 (ActionsManager.ACTION_CONTINUE); 160 } 161 162 public void stepOver () { 163 step (ActionsManager.ACTION_STEP_OVER); 164 } 165 166 public void stepInto () { 167 step (ActionsManager.ACTION_STEP_INTO); 168 } 169 170 public void stepOut () { 171 step (ActionsManager.ACTION_STEP_OUT); 172 } 173 174 public void step (Object action) { 175 if (jpdaDebugger.getState () != JPDADebugger.STATE_STOPPED) 176 throw new IllegalStateException (); 177 debuggerEngine.getActionsManager ().doAction (action); 178 waitState (JPDADebugger.STATE_STOPPED); 179 } 180 181 public void stepAsynch (final Object actionAsynch, final ActionsManagerListener al) { 182 if (jpdaDebugger.getState () != JPDADebugger.STATE_STOPPED) 183 throw new IllegalStateException (); 184 debuggerEngine.getActionsManager().addActionsManagerListener( 185 new ActionsManagerListener() { 186 public void actionPerformed(Object action) { 187 if (action != actionAsynch) return ; 188 al.actionPerformed(action); 189 debuggerEngine.getActionsManager().removeActionsManagerListener(this); 190 } 191 public void actionStateChanged(Object action, boolean enabled) { 192 } 193 } 194 ); 195 debuggerEngine.getActionsManager ().postAction (actionAsynch); 196 } 197 198 public void doFinish () { 199 if (jpdaDebugger == null) return; 200 debuggerEngine.getActionsManager (). 201 doAction (ActionsManager.ACTION_KILL); 202 waitState (JPDADebugger.STATE_DISCONNECTED); 203 } 204 205 public void waitState (int state) { 206 synchronized (STATE_LOCK) { 207 while ( jpdaDebugger.getState () != state && 208 jpdaDebugger.getState () != JPDADebugger.STATE_DISCONNECTED 209 ) { 210 try { 211 STATE_LOCK.wait (); 212 } catch (InterruptedException ex) { 213 ex.printStackTrace (); 214 } 215 } 216 } 217 } 218 219 public JPDADebugger getDebugger() { 220 return jpdaDebugger; 221 } 222 223 public static void removeAllBreakpoints () { 224 Breakpoint[] bs = DebuggerManager.getDebuggerManager (). 225 getBreakpoints (); 226 int i, k = bs.length; 227 for (i = 0; i < k; i++) 228 DebuggerManager.getDebuggerManager ().removeBreakpoint (bs [i]); 229 } 230 231 232 234 private static Object [] createServices () { 235 Map map = new HashMap (); 237 return new Object [] { 247 map 248 }; 249 } 253 254 private static String readLine (InputStream in) throws IOException { 255 StringBuffer sb = new StringBuffer (); 256 for (;;) { 257 int c = in.read(); 258 if (c == -1) throw new EOFException(); 259 if (c == 0x0D) { 260 c = in.read(); 261 if (c != 0x0A) sb.append((char)0x0D); 262 } 263 if (c == 0x0A) return sb.toString(); 264 sb.append((char)c); 265 } 266 } 267 268 private static Process launchVM ( 269 String mainClass, 270 String connectorAddress, 271 boolean server 272 ) throws IOException { 273 274 URLClassLoader ucl = (URLClassLoader ) JPDASupport.class. 275 getClassLoader (); 276 URL [] urls = ucl.getURLs (); 277 278 StringBuffer cp = new StringBuffer (200); 279 for (int i = 0; i < urls.length; i++) { 280 URL url = urls [i]; 281 cp.append (url.getPath ()); 282 cp.append (File.pathSeparatorChar); 283 } 284 285 String [] cmdArray = new String [] { 286 System.getProperty ("java.home") + File.separatorChar + 287 "bin" + File.separatorChar + "java", 288 "-Xdebug", 289 "-Xnoagent", 290 "-Xrunjdwp:transport=" + "dt_socket" + ",address=" + 291 connectorAddress + ",suspend=y,server=" + 292 (server ? "y" : "n"), 293 "-classpath", 294 cp.substring(0, cp.length() -1), 295 mainClass 296 }; 297 298 return Runtime.getRuntime ().exec (cmdArray); 299 } 300 301 public String toString () { 302 switch (jpdaDebugger.getState ()) { 303 case JPDADebugger.STATE_DISCONNECTED: 304 return "Debugger finished."; 305 case JPDADebugger.STATE_RUNNING: 306 return "Debugger running."; 307 case JPDADebugger.STATE_STARTING: 308 return "Debugger starting."; 309 case JPDADebugger.STATE_STOPPED: 310 CallStackFrame f = jpdaDebugger.getCurrentCallStackFrame (); 311 return "Debugger stopped: " + 312 f.getClassName () + "." + 313 f.getMethodName () + ":" + 314 f.getLineNumber (null); 315 } 316 return super.toString (); 317 } 318 319 321 public Breakpoint[] initBreakpoints() { 322 return new Breakpoint[0]; 323 } 324 325 public void breakpointAdded(Breakpoint breakpoint) { 326 } 327 328 public void breakpointRemoved(Breakpoint breakpoint) { 329 } 330 331 public void initWatches() { 332 } 333 334 public void watchAdded(Watch watch) { 335 } 336 337 public void watchRemoved(Watch watch) { 338 } 339 340 public void sessionAdded(Session session) { 341 } 342 343 public void sessionRemoved(Session session) { 344 } 345 346 public void propertyChange (PropertyChangeEvent evt) { 347 if (evt.getSource() instanceof JPDADebugger) { 348 JPDADebugger dbg = (JPDADebugger) evt.getSource(); 349 350 if (JPDADebugger.PROP_STATE.equals(evt.getPropertyName())) { 351 synchronized (STATE_LOCK) { 352 STATE_LOCK.notifyAll (); 353 } 354 if (jpdaDebugger.getState () == JPDADebugger.STATE_DISCONNECTED) 355 jpdaDebugger.removePropertyChangeListener (this); 356 } 357 } 358 } 359 360 public void engineAdded (DebuggerEngine debuggerEngine) { 362 } 363 364 public void engineRemoved (DebuggerEngine debuggerEngine) { 366 } 367 368 369 371 private static class ProcessIO { 372 373 private Process p; 374 375 public ProcessIO(Process p) { 376 this.p = p; 377 } 378 379 public void go() { 380 InputStream out = p.getInputStream(); 381 InputStream err = p.getErrorStream(); 382 383 new SimplePipe(System.out, out).start(); 384 new SimplePipe(System.out, err).start(); 385 } 386 } 387 388 private static class SimplePipe extends Thread { 389 private OutputStream out; 390 private InputStream in; 391 392 public SimplePipe(OutputStream out, InputStream in) { 393 this.out = out; 394 this.in = in; 395 setDaemon(true); 396 } 397 398 public void run() { 399 byte [] buffer = new byte[1024]; 400 int n; 401 try { 402 while ((n = in.read(buffer)) != -1) { 403 out.write(buffer, 0, n); 404 } 405 } catch (IOException e) { 406 } finally { 407 try { 408 out.close(); 409 in.close(); 410 } catch (IOException e) { 411 } 412 } 413 System.out.println("PIO QUIT"); 414 } 415 } 416 } 417 | Popular Tags |