1 19 20 package org.netbeans.modules.scripting.php.dbginterface; 21 22 import java.io.IOException ; 23 import java.net.ConnectException ; 24 import java.net.ServerSocket ; 25 import java.net.Socket ; 26 import java.net.SocketException ; 27 import java.net.SocketTimeoutException ; 28 import java.util.HashSet ; 29 import java.util.Iterator ; 30 import java.util.List ; 31 import java.util.Map ; 32 import java.util.Set ; 33 import java.util.concurrent.ConcurrentHashMap ; 34 import org.netbeans.api.debugger.ActionsManager; 35 import org.netbeans.api.debugger.DebuggerManager; 36 import org.netbeans.modules.scripting.php.dbginterface.api.DbgSourceMap; 37 import org.netbeans.modules.scripting.php.dbginterface.api.DebuggerStartException; 38 import org.netbeans.modules.scripting.php.dbginterface.api.VariableNode; 39 import org.netbeans.modules.scripting.php.dbginterface.breakpoints.BreakpointModel; 40 import org.netbeans.modules.scripting.php.dbginterface.models.CallStackModel; 41 import org.netbeans.modules.scripting.php.dbginterface.models.DebugFrame; 42 import org.netbeans.modules.scripting.php.dbginterface.models.ThreadsModel; 43 import org.netbeans.modules.scripting.php.dbginterface.models.Variable; 44 import org.netbeans.modules.scripting.php.dbginterface.models.VariablesModel; 45 import org.netbeans.modules.scripting.php.dbginterface.models.WatchesModel; 46 import org.netbeans.spi.debugger.ActionsProviderSupport; 47 import org.netbeans.spi.debugger.ContextProvider; 48 import org.netbeans.spi.debugger.DebuggerEngineProvider; 49 import org.netbeans.spi.viewmodel.TableModel; 50 import org.netbeans.spi.viewmodel.TreeModel; 51 import org.openide.ErrorManager; 52 import org.openide.loaders.DataObject; 53 import org.openide.util.RequestProcessor; 54 55 59 public class DbgDebuggerImpl extends ActionsProviderSupport { 60 public static final String BREAKPOINTS_VIEW_NAME = "BreakpointsView"; 61 public static final String CALLSTACK_VIEW_NAME = "CallStackView"; 62 public static final String LOCALS_VIEW_NAME = "LocalsView"; 63 public static final String SESSIONS_VIEW_NAME = "SessionsView"; 64 public static final String THREADS_VIEW_NAME = "ThreadsView"; 65 public static final String WATCHES_VIEW_NAME = "WatchesView"; 66 67 private static final int DBG_DEFAULT_PORT = 7869; 68 69 private ContextProvider contextProvider; 70 private ServerSocket server = null; 71 private int port; 72 private DbgServerLoop dbgServerLoop; 73 private DbgServerHandler currentScriptContext; 74 private Boolean finished = Boolean.FALSE; 75 76 77 public DbgDebuggerImpl(ContextProvider contextProvider) { 79 this.contextProvider = contextProvider; 80 } 81 82 public void start() { 83 createServerSocket(); 84 85 86 if (dbgServerLoop == null) { 87 dbgServerLoop = new DbgServerLoop(); 88 } 89 90 RequestProcessor.getDefault().post(dbgServerLoop); 91 } 92 93 94 public void stop() { 95 synchronized (finished) { 96 if (finished.booleanValue()) { 97 return; 98 } 99 100 finished = Boolean.TRUE; 101 } 102 103 if (dbgServerLoop != null) { 104 dbgServerLoop.setStop(); 105 dbgServerLoop.notifyWait(); 106 107 dbgServerLoop = null; 108 } 109 110 ((DbgEngineProvider)contextProvider.lookupFirst(null, DebuggerEngineProvider.class)).getDestructor().killEngine(); 111 } 112 113 114 public void closeServerSocket() throws IOException { 115 if (server != null) { 116 stop(); 117 server = null; 118 } 119 } 120 121 public int getPort() { 122 return port; 123 } 124 125 public void waitRunning() throws DebuggerStartException { 126 start(); 127 } 128 129 public String getHost() { 130 return "localhost"; 132 } 133 134 public CallStackModel getCallStackModel() { 135 return (CallStackModel)contextProvider.lookupFirst(CALLSTACK_VIEW_NAME, TreeModel.class); 136 } 137 138 public ThreadsModel getThreadsModel() { 139 return (ThreadsModel)contextProvider.lookupFirst(THREADS_VIEW_NAME, TreeModel.class); 140 } 141 142 public VariablesModel getVariablesModel() { 143 return (VariablesModel)contextProvider.lookupFirst(LOCALS_VIEW_NAME, TreeModel.class); 144 } 145 146 public WatchesModel getWatchesModel() { 147 return (WatchesModel)contextProvider.lookupFirst(WATCHES_VIEW_NAME, TreeModel.class); 148 } 149 150 public BreakpointModel getBreakpointModel() { 151 Iterator it = DebuggerManager.getDebuggerManager().lookup(BREAKPOINTS_VIEW_NAME, TableModel.class).iterator(); 152 153 while(it.hasNext()) { 154 TableModel model = (TableModel)it.next(); 155 if (model instanceof BreakpointModel) { 156 return (BreakpointModel) model; 157 } 158 } 159 160 return null; 161 } 162 163 public VariableNode evaluateExpr(DebugFrame frame, String expr) { 164 Context c = getCurrentScriptContext(); 165 166 if (c == null) { 167 return null; 168 } 169 170 return c.evaluateExpr(frame, expr); 171 } 172 173 public DataObject getDataObject(String sourceFile) { 174 DbgSourceMap sourceMap = (DbgSourceMap)contextProvider.lookupFirst(null, DbgSourceMap.class); 175 176 if (sourceMap == null) { 177 return null; 178 } 179 180 return sourceMap.mapToSourceFileDataObject(sourceFile); 181 } 182 183 187 public void setEnableContActions(boolean s) { 188 setEnabled(ActionsManager.ACTION_CONTINUE, s); 189 setEnabled(ActionsManager.ACTION_STEP_INTO, s); 190 setEnabled(ActionsManager.ACTION_STEP_OVER, s); 191 setEnabled(ActionsManager.ACTION_STEP_OUT, s); 192 } 193 194 private static final Set <Object > ACTIONS = new HashSet <Object >(); 195 196 static { 197 ACTIONS.add(ActionsManager.ACTION_KILL); 198 ACTIONS.add(ActionsManager.ACTION_CONTINUE); 199 ACTIONS.add(ActionsManager.ACTION_START); 200 ACTIONS.add(ActionsManager.ACTION_STEP_INTO); 201 ACTIONS.add(ActionsManager.ACTION_STEP_OVER); 202 ACTIONS.add(ActionsManager.ACTION_STEP_OUT); 203 } 205 206 public Set getActions() { 207 return ACTIONS; 208 } 209 210 public void doAction(Object action) { 211 System.err.println("mw DbgDebuggerImpl.doAction(" + action + ")"); 212 if (action == ActionsManager.ACTION_KILL) { 213 stop(); 214 } 215 else { 216 DbgDebuggerImpl.Context context = getCurrentScriptContext(); 217 218 System.err.println("mw DbgDebuggerImpl.doAction() context= " + context); 219 220 if(context == null) { 221 return; 222 } 223 224 if (action == ActionsManager.ACTION_CONTINUE) { 225 getVariablesModel().clearModel(); 226 getWatchesModel().setStackFrame(null); 227 context.resume(); 228 } 229 else if (action == ActionsManager.ACTION_STEP_INTO) { 230 context.stepInto(); 231 } 232 else if (action == ActionsManager.ACTION_STEP_OUT) { 233 context.stepOut(); 234 } 235 else if (action == ActionsManager.ACTION_STEP_OVER) { 236 context.stepOver(); 237 } 238 260 } 261 } 262 263 public Context[] getScriptContexts() { 264 Set <DbgServerHandler> set = dbgServerLoop.getHandlerSet().keySet(); 265 266 return set.toArray(new Context[set.size()]); 267 } 268 269 public void closeScriptContext(Context context) { 270 DbgServerHandler handler = (DbgServerHandler)context; 271 272 handler.stop(); 273 dbgServerLoop.getHandlerSet().remove(handler); 274 275 276 if (currentScriptContext == handler) { 277 DbgServerHandler replacement = null; 278 279 if (!dbgServerLoop.getHandlerSet().isEmpty()) { 280 replacement = (DbgServerHandler)dbgServerLoop.getHandlerSet().keySet().toArray()[0]; 281 setCurrentScriptContext(replacement); 282 } 283 else { 284 stop(); 285 286 return; 287 } 288 } 289 else { 290 getThreadsModel().setNeedsRefresh(); 291 } 292 293 getThreadsModel().refresh(false); 296 } 297 298 299 public Context getCurrentScriptContext() { 300 return currentScriptContext; 301 } 302 303 public void setCurrentScriptContext(Context context) { 304 if(currentScriptContext == context) { 305 return; 306 } 307 308 if(currentScriptContext != null) { 309 currentScriptContext.hideCurrentLine(); 310 } 311 312 currentScriptContext = (DbgServerHandler)context; 313 314 if(currentScriptContext != null) { 315 currentScriptContext.handleCurrentLine(); 316 setEnabled(ActionsManager.ACTION_KILL, true); 317 } 318 319 getThreadsModel().setNeedsRefresh(); 320 getCallStackModel().setNeedsRefresh(); 321 } 322 323 public DbgSourceMap getSourceMap() { 324 return (DbgSourceMap)contextProvider.lookupFirst(null, DbgSourceMap.class); 325 } 326 327 public static abstract class Context { 328 private DbgDebuggerImpl server; 329 330 protected Context(DbgDebuggerImpl impl) { 331 this.server = impl; 332 } 333 334 public DbgDebuggerImpl getServer() { 335 return server; 336 } 337 338 public abstract boolean isSuspended(); 339 340 public abstract List <DebugFrame> getCallStack(); 341 342 public abstract Variable getScopeVariables(DebugFrame frame); 343 344 public abstract void setVariableValue(DebugFrame frame, Variable v, Object value); 345 346 public abstract Variable evaluateExpr(DebugFrame frame, String expr); 347 public abstract void resume(); 348 349 public abstract void stepInto(); 350 351 public abstract void stepOut(); 352 353 public abstract void stepOver(); 354 355 public boolean isCurrent() { 356 return server.getCurrentScriptContext() == this; 357 } 358 } 359 360 private void createServerSocket() { 361 if (server == null) { 362 port = findFreePort(); 363 364 if (port == -1) { 365 ErrorManager.getDefault(). 366 log(ErrorManager.WARNING, "DbgServer.createServerSocket(): could not find free port!"); 367 368 return; 369 } 370 371 try { 372 server = new ServerSocket (port); 373 server.setSoTimeout(60000); } 375 catch (IOException ioe) { 376 ErrorManager.getDefault(). 377 log(ErrorManager.WARNING, "DbgServer.createServerSocket(): could not create server socket!"); 378 ErrorManager.getDefault(). 379 notify(ErrorManager.WARNING, ioe); 380 381 stop(); 382 } 383 } 384 } 385 386 387 private int findFreePort() { 388 for (int port = DBG_DEFAULT_PORT; port < DBG_DEFAULT_PORT + 100; port++) { 389 Socket testClient = null; 390 391 try { 392 testClient = new Socket ("localhost", port); } 394 catch (ConnectException ce) { 395 return port; 396 } 397 catch (IOException ioe) { 398 ioe.printStackTrace(System.err); 399 } 401 finally { 402 if (testClient != null) { 403 try { 405 testClient.close(); 406 } 407 catch (IOException ioe) { 408 } 410 } 411 } 412 } 413 414 return -1; 415 } 416 417 418 private class DbgServerLoop implements Runnable { 419 private boolean stop; 420 private Map <DbgServerHandler, Boolean > handlerSet = new ConcurrentHashMap <DbgServerHandler, Boolean >(); 421 422 public DbgServerLoop() { 423 stop = false; 424 } 425 426 public Map <DbgServerHandler, Boolean > getHandlerSet() { 427 return handlerSet; 428 } 429 430 public synchronized void setStop() { 431 stop = true; 432 433 try { 435 server.close(); 436 } 437 catch (IOException ioe) { 438 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ioe); 439 } 440 } 441 442 public synchronized void notifyWait() { 443 notify(); 444 } 445 446 public void run() { 447 try { 448 while (!stop && !server.isClosed()) { 450 Socket handlerSocket = null; 451 452 try { 453 handlerSocket = server.accept(); 454 System.err.println("DbgServerLoop.run().Accepted! : " + handlerSocket.toString()); 455 } 456 catch (SocketTimeoutException ste) { 457 } 459 catch (SocketException se) { 460 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, se); 462 463 return; 464 } 465 catch (IOException ioe) { 466 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ioe); 467 468 return; 469 } 470 471 if (handlerSocket != null) { 472 DbgServerHandler h = new DbgServerHandler(DbgDebuggerImpl.this, handlerSocket); 474 475 handlerSet.put(h, Boolean.TRUE); 476 RequestProcessor.getDefault().post(h); 477 DbgDebuggerImpl.this.setCurrentScriptContext(h); 478 } 479 } 480 } 481 catch (Exception ex) { 482 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); 483 } finally { 484 try { 485 for (DbgServerHandler h : handlerSet.keySet()) { 486 h.stop(); 487 } 488 489 server.close(); 490 } 491 catch (IOException ioe) { 492 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ioe); 493 494 return; 495 } 496 497 } 499 } 500 } 501 } 502 | Popular Tags |