1 19 20 package org.netbeans.api.debugger.jpda; 21 import java.io.File ; 22 import java.io.FileInputStream ; 23 import java.io.FileNotFoundException ; 24 import java.io.FileOutputStream ; 25 import java.io.IOException ; 26 import java.io.UnsupportedEncodingException ; 27 import java.net.URL ; 28 import junit.framework.AssertionFailedError; 29 import org.netbeans.api.debugger.DebuggerManager; 30 import org.netbeans.api.debugger.jpda.event.JPDABreakpointEvent; 31 import org.netbeans.api.debugger.jpda.event.JPDABreakpointListener; 32 import org.netbeans.junit.NbTestCase; 33 34 35 47 public class JspLineBreakpointTest extends NbTestCase { 48 49 private static final String SOURCE_NAME = "included.jsp"; 50 private static final String SOURCE_PATH_FIRST = "d/" + SOURCE_NAME; 51 private static final String SOURCE_PATH_SECOND = SOURCE_NAME; 52 private static final String CLASS_NAME = "org.netbeans.api.debugger.jpda.testapps.*"; 53 private static final int LINE_NUMBER = 2; 54 private static final String STRATUM = "JSP"; 55 56 private JPDASupport support; 57 private String testAppCLAZ = null; 58 private String testAppSMAP = null; 59 60 public JspLineBreakpointTest (String s) { 61 super (s); 62 } 63 64 protected void setUp () { 65 URL clazURL = getClass ().getResource ("testapps/JspLineBreakpointApp.class"); 66 assertNotNull (clazURL); 67 testAppCLAZ = clazURL.getPath(); 68 URL smapURL = getClass ().getResource ("testapps/JspLineBreakpointApp.txt"); 69 assertNotNull (smapURL); 70 testAppSMAP = smapURL.getPath(); 71 } 72 73 85 public void testBreakpointUnambiguity () throws Exception { 86 try { 87 runSDEInstaller(testAppCLAZ, testAppSMAP); 89 90 String URL = getClass().getResource("testapps/resources/included.jsp").toString(); 91 LineBreakpoint lb = LineBreakpoint.create(URL, LINE_NUMBER); 92 lb.setStratum(STRATUM); lb.setSourceName(SOURCE_NAME); 94 lb.setSourcePath(SOURCE_PATH_SECOND); 95 lb.setPreferredClassName(CLASS_NAME); 96 97 DebuggerManager dm = DebuggerManager.getDebuggerManager (); 98 dm.addBreakpoint (lb); 99 100 support = JPDASupport.attach ( 101 "org.netbeans.api.debugger.jpda.testapps.JspLineBreakpointApp" 102 ); 103 JPDADebugger debugger = support.getDebugger(); 104 105 support.waitState (JPDADebugger.STATE_STOPPED); assertNotNull(debugger.getCurrentCallStackFrame()); 107 assertEquals( 108 "Debugger stopped at wrong file", 109 lb.getSourcePath(), 110 debugger.getCurrentCallStackFrame().getSourcePath(STRATUM) 111 ); 112 113 dm.removeBreakpoint (lb); 114 } finally { 115 if (support != null) support.doFinish (); 116 } 117 } 118 119 131 public void testBreakpointRepeatability () throws Exception { 132 try { 133 runSDEInstaller(testAppCLAZ, testAppSMAP); 135 136 String URL = getClass().getResource("testapps/resources/included.jsp").toString(); 137 LineBreakpoint lb = LineBreakpoint.create(URL, LINE_NUMBER); 138 lb.setStratum(STRATUM); lb.setSourceName(SOURCE_NAME); 140 lb.setSourcePath(SOURCE_PATH_SECOND); 141 lb.setPreferredClassName(CLASS_NAME); 142 143 DebuggerManager dm = DebuggerManager.getDebuggerManager (); 144 dm.addBreakpoint (lb); 145 146 support = JPDASupport.attach ( 147 "org.netbeans.api.debugger.jpda.testapps.JspLineBreakpointApp" 148 ); 149 JPDADebugger debugger = support.getDebugger(); 150 151 support.waitState (JPDADebugger.STATE_STOPPED); support.doContinue (); 153 support.waitState (JPDADebugger.STATE_STOPPED); assertTrue( 155 "Debugger did not stop at breakpoint for the second time.", 156 debugger.getState() == JPDADebugger.STATE_STOPPED 157 ); 158 159 dm.removeBreakpoint (lb); 160 161 } finally { 162 if (support != null) support.doFinish (); 163 } 164 } 165 166 private static void runSDEInstaller(String pathToClassFile, String pathToSmapFile) throws IOException { 167 SDEInstaller.main(new String [] { pathToClassFile, pathToSmapFile }); 168 } 169 170 172 private static class SDEInstaller { 173 174 static final String nameSDE = "SourceDebugExtension"; 175 176 byte[] orig; 177 byte[] sdeAttr; 178 byte[] gen; 179 180 int origPos = 0; 181 int genPos = 0; 182 183 int sdeIndex; 184 185 private boolean isDebugEnabled() { 186 return System.getProperty("sde.SDEInstaller.verbose") != null; 187 } 188 189 public static void main(String [] args) throws IOException { 190 if (args.length == 2) { 191 install(new File (args[0]), new File (args[1])); 192 } else if (args.length == 3) { 193 install( 194 new File (args[0]), 195 new File (args[1]), 196 new File (args[2])); 197 } else { 198 System.err.println( 199 "Usage: <command> <input class file> " 200 + "<attribute file> <output class file name>\n" 201 + "<command> <input/output class file> <attribute file>"); 202 } 203 } 204 205 static void install(File inClassFile, File attrFile, File outClassFile) 206 throws IOException { 207 new SDEInstaller(inClassFile, attrFile, outClassFile); 208 } 209 210 static void install(File inOutClassFile, File attrFile) 211 throws IOException { 212 File tmpFile = new File (inOutClassFile.getPath() + "tmp"); 213 new SDEInstaller(inOutClassFile, attrFile, tmpFile); 214 if (!inOutClassFile.delete()) { 215 throw new IOException ("inOutClassFile.delete() failed"); 216 } 217 if (!tmpFile.renameTo(inOutClassFile)) { 218 throw new IOException ("tmpFile.renameTo(inOutClassFile) failed"); 219 } 220 } 221 222 static void install(File classFile, byte[] smap) throws IOException { 223 File tmpFile = new File (classFile.getPath() + "tmp"); 224 new SDEInstaller(classFile, smap, tmpFile); 225 if (!classFile.delete()) { 226 throw new IOException ("classFile.delete() failed"); 227 } 228 if (!tmpFile.renameTo(classFile)) { 229 throw new IOException ("tmpFile.renameTo(classFile) failed"); 230 } 231 } 232 233 SDEInstaller(File inClassFile, byte[] sdeAttr, File outClassFile) 234 throws IOException { 235 if (!inClassFile.exists()) { 236 throw new FileNotFoundException ("no such file: " + inClassFile); 237 } 238 239 this.sdeAttr = sdeAttr; 240 orig = readWhole(inClassFile); 242 gen = new byte[orig.length + sdeAttr.length + 100]; 243 244 addSDE(); 246 247 FileOutputStream outStream = new FileOutputStream (outClassFile); 249 outStream.write(gen, 0, genPos); 250 outStream.close(); 251 } 252 253 SDEInstaller(File inClassFile, File attrFile, File outClassFile) 254 throws IOException { 255 this(inClassFile, readWhole(attrFile), outClassFile); 256 } 257 258 static byte[] readWhole(File input) throws IOException { 259 FileInputStream inStream = new FileInputStream (input); 260 int len = (int)input.length(); 261 byte[] bytes = new byte[len]; 262 if (inStream.read(bytes, 0, len) != len) { 263 throw new IOException ("expected size: " + len); 264 } 265 inStream.close(); 266 return bytes; 267 } 268 269 void addSDE() throws UnsupportedEncodingException , IOException { 270 int i; 271 copy(4 + 2 + 2); int constantPoolCountPos = genPos; 273 int constantPoolCount = readU2(); 274 if (isDebugEnabled()) 275 System.out.println("constant pool count: " + constantPoolCount); 276 writeU2(constantPoolCount); 277 278 sdeIndex = copyConstantPool(constantPoolCount); 280 if (sdeIndex < 0) { 281 writeUtf8ForSDE(); 283 284 sdeIndex = constantPoolCount; 286 ++constantPoolCount; 287 randomAccessWriteU2(constantPoolCountPos, constantPoolCount); 288 289 if (isDebugEnabled()) 290 System.out.println("SourceDebugExtension not found, installed at: " + sdeIndex); 291 } else { 292 if (isDebugEnabled()) 293 System.out.println("SourceDebugExtension found at: " + sdeIndex); 294 } 295 copy(2 + 2 + 2); int interfaceCount = readU2(); 297 writeU2(interfaceCount); 298 if (isDebugEnabled()) 299 System.out.println("interfaceCount: " + interfaceCount); 300 copy(interfaceCount * 2); 301 copyMembers(); copyMembers(); int attrCountPos = genPos; 304 int attrCount = readU2(); 305 writeU2(attrCount); 306 if (isDebugEnabled()) 307 System.out.println("class attrCount: " + attrCount); 308 if (!copyAttrs(attrCount)) { 310 ++attrCount; 312 randomAccessWriteU2(attrCountPos, attrCount); 313 if (isDebugEnabled()) 314 System.out.println("class attrCount incremented"); 315 } 316 writeAttrForSDE(sdeIndex); 317 } 318 319 void copyMembers() { 320 int count = readU2(); 321 writeU2(count); 322 if (isDebugEnabled()) 323 System.out.println("members count: " + count); 324 for (int i = 0; i < count; ++i) { 325 copy(6); int attrCount = readU2(); 327 writeU2(attrCount); 328 if (isDebugEnabled()) 329 System.out.println("member attr count: " + attrCount); 330 copyAttrs(attrCount); 331 } 332 } 333 334 boolean copyAttrs(int attrCount) { 335 boolean sdeFound = false; 336 for (int i = 0; i < attrCount; ++i) { 337 int nameIndex = readU2(); 338 if (nameIndex == sdeIndex) { 340 sdeFound = true; 341 if (isDebugEnabled()) 342 System.out.println("SDE attr found"); 343 } else { 344 writeU2(nameIndex); int len = readU4(); 346 writeU4(len); 347 copy(len); 348 if (isDebugEnabled()) 349 System.out.println("attr len: " + len); 350 } 351 } 352 return sdeFound; 353 } 354 355 void writeAttrForSDE(int index) { 356 writeU2(index); 357 writeU4(sdeAttr.length); 358 for (int i = 0; i < sdeAttr.length; ++i) { 359 writeU1(sdeAttr[i]); 360 } 361 } 362 363 void randomAccessWriteU2(int pos, int val) { 364 int savePos = genPos; 365 genPos = pos; 366 writeU2(val); 367 genPos = savePos; 368 } 369 370 int readU1() { 371 return ((int)orig[origPos++]) & 0xFF; 372 } 373 374 int readU2() { 375 int res = readU1(); 376 return (res << 8) + readU1(); 377 } 378 379 int readU4() { 380 int res = readU2(); 381 return (res << 16) + readU2(); 382 } 383 384 void writeU1(int val) { 385 gen[genPos++] = (byte)val; 386 } 387 388 void writeU2(int val) { 389 writeU1(val >> 8); 390 writeU1(val & 0xFF); 391 } 392 393 void writeU4(int val) { 394 writeU2(val >> 16); 395 writeU2(val & 0xFFFF); 396 } 397 398 void copy(int count) { 399 for (int i = 0; i < count; ++i) { 400 gen[genPos++] = orig[origPos++]; 401 } 402 } 403 404 byte[] readBytes(int count) { 405 byte[] bytes = new byte[count]; 406 for (int i = 0; i < count; ++i) { 407 bytes[i] = orig[origPos++]; 408 } 409 return bytes; 410 } 411 412 void writeBytes(byte[] bytes) { 413 for (int i = 0; i < bytes.length; ++i) { 414 gen[genPos++] = bytes[i]; 415 } 416 } 417 418 int copyConstantPool(int constantPoolCount) 419 throws UnsupportedEncodingException , IOException { 420 int sdeIndex = -1; 421 for (int i = 1; i < constantPoolCount; ++i) { 423 int tag = readU1(); 424 writeU1(tag); 425 switch (tag) { 426 case 7 : case 8 : if (isDebugEnabled()) 429 System.out.println(i + " copying 2 bytes"); 430 copy(2); 431 break; 432 case 9 : case 10 : case 11 : case 3 : case 4 : case 12 : if (isDebugEnabled()) 439 System.out.println(i + " copying 4 bytes"); 440 copy(4); 441 break; 442 case 5 : case 6 : if (isDebugEnabled()) 445 System.out.println(i + " copying 8 bytes"); 446 copy(8); 447 i++; 448 break; 449 case 1 : int len = readU2(); 451 writeU2(len); 452 byte[] utf8 = readBytes(len); 453 String str = new String (utf8, "UTF-8"); 454 if (isDebugEnabled()) 455 System.out.println(i + " read class attr -- '" + str + "'"); 456 if (str.equals(nameSDE)) { 457 sdeIndex = i; 458 } 459 writeBytes(utf8); 460 break; 461 default : 462 throw new IOException ("unexpected tag: " + tag); 463 } 464 } 465 return sdeIndex; 466 } 467 468 void writeUtf8ForSDE() { 469 int len = nameSDE.length(); 470 writeU1(1); writeU2(len); 472 for (int i = 0; i < len; ++i) { 473 writeU1(nameSDE.charAt(i)); 474 } 475 } 476 } 477 478 private class TestBreakpointListener implements JPDABreakpointListener { 479 480 private LineBreakpoint lineBreakpoint; 481 private int conditionResult; 482 483 private JPDABreakpointEvent event; 484 private AssertionError failure; 485 486 public TestBreakpointListener (LineBreakpoint lineBreakpoint) { 487 this (lineBreakpoint, JPDABreakpointEvent.CONDITION_NONE); 488 } 489 490 public TestBreakpointListener ( 491 LineBreakpoint lineBreakpoint, 492 int conditionResult 493 ) { 494 this.lineBreakpoint = lineBreakpoint; 495 this.conditionResult = conditionResult; 496 } 497 498 public void breakpointReached (JPDABreakpointEvent event) { 499 try { 500 checkEvent (event); 501 } catch (AssertionError e) { 502 failure = e; 503 } catch (Throwable e) { 504 failure = new AssertionError (e); 505 } 506 } 507 508 private void checkEvent (JPDABreakpointEvent event) { 509 this.event = event; 510 assertEquals ( 511 "Breakpoint event: Wrong source breakpoint", 512 lineBreakpoint, 513 event.getSource () 514 ); 515 assertNotNull ( 516 "Breakpoint event: Context thread is null", 517 event.getThread () 518 ); 519 520 int result = event.getConditionResult (); 521 if ( result == JPDABreakpointEvent.CONDITION_FAILED && 522 conditionResult != JPDABreakpointEvent.CONDITION_FAILED 523 ) 524 failure = new AssertionError (event.getConditionException ()); 525 else 526 if (result != conditionResult) 527 failure = new AssertionError ( 528 "Unexpected breakpoint condition result: " + result 529 ); 530 } 531 532 public void checkResult () { 533 if (event == null) { 534 CallStackFrame f = support.getDebugger (). 535 getCurrentCallStackFrame (); 536 int ln = -1; 537 if (f != null) { 538 ln = f.getLineNumber (null); 539 } 540 throw new AssertionError ( 541 "Breakpoint was not hit (listener was not notified) " + ln 542 ); 543 } 544 if (failure != null) throw failure; 545 } 546 } 547 548 } 549 | Popular Tags |