KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > api > debugger > jpda > JspLineBreakpointTest


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.api.debugger.jpda;
21 import java.io.File JavaDoc;
22 import java.io.FileInputStream JavaDoc;
23 import java.io.FileNotFoundException JavaDoc;
24 import java.io.FileOutputStream JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.UnsupportedEncodingException JavaDoc;
27 import java.net.URL JavaDoc;
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 /**
36  * Tests JSP line breakpoints at various circumstances.
37  *
38  * The tests use test java application (JspLineBreakpointApp.java) created
39  * from servlet generated by Tomcat's JSP compiler. The java app has all necessary
40  * lines left on the same place as original servlet. In addition SMAP file (JspLineBreakpointApp.txt)
41  * is attached to java app (class file) to support mapping from lines in java source
42  * to lines in JSP, from which the servlet was translated. The JSP pages are placed in
43  * org/netbeans/api/debugger/jpda/testapps/resources directory.
44  *
45  * @author Libor Kotouc
46  */

47 public class JspLineBreakpointTest extends NbTestCase {
48
49     private static final String JavaDoc SOURCE_NAME = "included.jsp";
50     private static final String JavaDoc SOURCE_PATH_FIRST = "d/" + SOURCE_NAME;
51     private static final String JavaDoc SOURCE_PATH_SECOND = SOURCE_NAME;
52     private static final String JavaDoc CLASS_NAME = "org.netbeans.api.debugger.jpda.testapps.*";
53     private static final int LINE_NUMBER = 2;
54     private static final String JavaDoc STRATUM = "JSP";
55     
56     private JPDASupport support;
57     private String JavaDoc testAppCLAZ = null;
58     private String JavaDoc testAppSMAP = null;
59     
60     public JspLineBreakpointTest (String JavaDoc s) {
61         super (s);
62     }
63     
64     protected void setUp () {
65         URL JavaDoc clazURL = getClass ().getResource ("testapps/JspLineBreakpointApp.class");
66         assertNotNull (clazURL);
67         testAppCLAZ = clazURL.getPath();
68         URL JavaDoc smapURL = getClass ().getResource ("testapps/JspLineBreakpointApp.txt");
69         assertNotNull (smapURL);
70         testAppSMAP = smapURL.getPath();
71     }
72     
73     /**
74      * Tests debugger's ability to make difference between different JSP pages
75      * with the same name while getting the locations during class-loaded event.
76      *
77      * 1. The user creates JSP (index.jsp, include.jsp, d/include.jsp) and
78      * 2. statically includes d/include.jsp (as 1st) and include.jsp (as 2nd) into index.jsp.
79      * 3. Then bp is set in include.jsp (line 2).
80      *
81      * Debugger should stop _only_ in the include.jsp. If debugger stopped in the first JSP
82      * (d/include.jsp), then assertion violation would arise because of source path
83      * equality test.
84      */

85     public void testBreakpointUnambiguity () throws Exception JavaDoc {
86         try {
87             //install SDE extension to class file
88
runSDEInstaller(testAppCLAZ, testAppSMAP);
89
90             String JavaDoc URL = getClass().getResource("testapps/resources/included.jsp").toString();
91             LineBreakpoint lb = LineBreakpoint.create(URL, LINE_NUMBER);
92             lb.setStratum(STRATUM); // NOI18N
93
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); // breakpoint hit
106
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     /**
120      * Tests debugger's ability to stop in one JSP as many times as this JSP
121      * is included in another page.
122      *
123      * 1. The user creates JSP (index.jsp, include.jsp) and
124      * 2. statically includes include.jsp twice into index.jsp.
125      * 3. Then bp is set in include.jsp (line 2).
126      *
127      * Debugger should stop twice in the include.jsp. If debugger didn't stopped
128      * in the include.jsp for the second time, then assertion violation would arise
129      * because of testing debugger's state for STOP state.
130      */

131     public void testBreakpointRepeatability () throws Exception JavaDoc {
132         try {
133             //install SDE extension to class file
134
runSDEInstaller(testAppCLAZ, testAppSMAP);
135
136             String JavaDoc URL = getClass().getResource("testapps/resources/included.jsp").toString();
137             LineBreakpoint lb = LineBreakpoint.create(URL, LINE_NUMBER);
138             lb.setStratum(STRATUM); // NOI18N
139
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); // first breakpoint hit
152
support.doContinue ();
153             support.waitState (JPDADebugger.STATE_STOPPED); // second breakpoint hit
154
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 JavaDoc pathToClassFile, String JavaDoc pathToSmapFile) throws IOException JavaDoc {
167         SDEInstaller.main(new String JavaDoc[] { pathToClassFile, pathToSmapFile });
168     }
169
170 //inner classes
171

172     private static class SDEInstaller {
173
174         static final String JavaDoc 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 JavaDoc[] args) throws IOException JavaDoc {
190             if (args.length == 2) {
191                 install(new File JavaDoc(args[0]), new File JavaDoc(args[1]));
192             } else if (args.length == 3) {
193                 install(
194                     new File JavaDoc(args[0]),
195                     new File JavaDoc(args[1]),
196                     new File JavaDoc(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 JavaDoc inClassFile, File JavaDoc attrFile, File JavaDoc outClassFile)
206             throws IOException JavaDoc {
207             new SDEInstaller(inClassFile, attrFile, outClassFile);
208         }
209
210         static void install(File JavaDoc inOutClassFile, File JavaDoc attrFile)
211             throws IOException JavaDoc {
212             File JavaDoc tmpFile = new File JavaDoc(inOutClassFile.getPath() + "tmp");
213             new SDEInstaller(inOutClassFile, attrFile, tmpFile);
214             if (!inOutClassFile.delete()) {
215                 throw new IOException JavaDoc("inOutClassFile.delete() failed");
216             }
217             if (!tmpFile.renameTo(inOutClassFile)) {
218                 throw new IOException JavaDoc("tmpFile.renameTo(inOutClassFile) failed");
219             }
220         }
221
222         static void install(File JavaDoc classFile, byte[] smap) throws IOException JavaDoc {
223             File JavaDoc tmpFile = new File JavaDoc(classFile.getPath() + "tmp");
224             new SDEInstaller(classFile, smap, tmpFile);
225             if (!classFile.delete()) {
226                 throw new IOException JavaDoc("classFile.delete() failed");
227             }
228             if (!tmpFile.renameTo(classFile)) {
229                 throw new IOException JavaDoc("tmpFile.renameTo(classFile) failed");
230             }
231         }
232
233         SDEInstaller(File JavaDoc inClassFile, byte[] sdeAttr, File JavaDoc outClassFile)
234             throws IOException JavaDoc {
235             if (!inClassFile.exists()) {
236                 throw new FileNotFoundException JavaDoc("no such file: " + inClassFile);
237             }
238
239             this.sdeAttr = sdeAttr;
240             // get the bytes
241
orig = readWhole(inClassFile);
242             gen = new byte[orig.length + sdeAttr.length + 100];
243
244             // do it
245
addSDE();
246
247             // write result
248
FileOutputStream JavaDoc outStream = new FileOutputStream JavaDoc(outClassFile);
249             outStream.write(gen, 0, genPos);
250             outStream.close();
251         }
252
253         SDEInstaller(File JavaDoc inClassFile, File JavaDoc attrFile, File JavaDoc outClassFile)
254             throws IOException JavaDoc {
255             this(inClassFile, readWhole(attrFile), outClassFile);
256         }
257
258         static byte[] readWhole(File JavaDoc input) throws IOException JavaDoc {
259             FileInputStream JavaDoc inStream = new FileInputStream JavaDoc(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 JavaDoc("expected size: " + len);
264             }
265             inStream.close();
266             return bytes;
267         }
268
269         void addSDE() throws UnsupportedEncodingException JavaDoc, IOException JavaDoc {
270             int i;
271             copy(4 + 2 + 2); // magic min/maj version
272
int constantPoolCountPos = genPos;
273             int constantPoolCount = readU2();
274             if (isDebugEnabled())
275                 System.out.println("constant pool count: " + constantPoolCount);
276             writeU2(constantPoolCount);
277
278             // copy old constant pool return index of SDE symbol, if found
279
sdeIndex = copyConstantPool(constantPoolCount);
280             if (sdeIndex < 0) {
281                 // if "SourceDebugExtension" symbol not there add it
282
writeUtf8ForSDE();
283
284                 // increment the countantPoolCount
285
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); // access, this, super
296
int interfaceCount = readU2();
297             writeU2(interfaceCount);
298             if (isDebugEnabled())
299                 System.out.println("interfaceCount: " + interfaceCount);
300             copy(interfaceCount * 2);
301             copyMembers(); // fields
302
copyMembers(); // methods
303
int attrCountPos = genPos;
304             int attrCount = readU2();
305             writeU2(attrCount);
306             if (isDebugEnabled())
307                 System.out.println("class attrCount: " + attrCount);
308             // copy the class attributes, return true if SDE attr found (not copied)
309
if (!copyAttrs(attrCount)) {
310                 // we will be adding SDE and it isn't already counted
311
++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); // access, name, descriptor
326
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                 // don't write old SDE
339
if (nameIndex == sdeIndex) {
340                     sdeFound = true;
341                     if (isDebugEnabled())
342                         System.out.println("SDE attr found");
343                 } else {
344                     writeU2(nameIndex); // name
345
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 JavaDoc, IOException JavaDoc {
420             int sdeIndex = -1;
421             // copy const pool index zero not in class file
422
for (int i = 1; i < constantPoolCount; ++i) {
423                 int tag = readU1();
424                 writeU1(tag);
425                 switch (tag) {
426                     case 7 : // Class
427
case 8 : // String
428
if (isDebugEnabled())
429                             System.out.println(i + " copying 2 bytes");
430                         copy(2);
431                         break;
432                     case 9 : // Field
433
case 10 : // Method
434
case 11 : // InterfaceMethod
435
case 3 : // Integer
436
case 4 : // Float
437
case 12 : // NameAndType
438
if (isDebugEnabled())
439                             System.out.println(i + " copying 4 bytes");
440                         copy(4);
441                         break;
442                     case 5 : // Long
443
case 6 : // Double
444
if (isDebugEnabled())
445                             System.out.println(i + " copying 8 bytes");
446                         copy(8);
447                         i++;
448                         break;
449                     case 1 : // Utf8
450
int len = readU2();
451                         writeU2(len);
452                         byte[] utf8 = readBytes(len);
453                         String JavaDoc str = new String JavaDoc(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 JavaDoc("unexpected tag: " + tag);
463                 }
464             }
465             return sdeIndex;
466         }
467
468         void writeUtf8ForSDE() {
469             int len = nameSDE.length();
470             writeU1(1); // Utf8 tag
471
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 JavaDoc 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 JavaDoc e) {
502                 failure = e;
503             } catch (Throwable JavaDoc e) {
504                 failure = new AssertionError JavaDoc (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 JavaDoc (event.getConditionException ());
525             else
526             if (result != conditionResult)
527                 failure = new AssertionError JavaDoc (
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 JavaDoc (
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