1 17 18 package org.apache.jasper.compiler; 19 20 import java.io.File ; 21 import java.io.FileInputStream ; 22 import java.io.FileNotFoundException ; 23 import java.io.FileOutputStream ; 24 import java.io.IOException ; 25 import java.io.OutputStreamWriter ; 26 import java.io.PrintWriter ; 27 import java.io.UnsupportedEncodingException ; 28 import java.util.HashMap ; 29 import java.util.Iterator ; 30 import java.util.Map ; 31 32 import org.apache.jasper.JasperException; 33 import org.apache.jasper.JspCompilationContext; 34 35 45 public class SmapUtil { 46 47 private org.apache.commons.logging.Log log= 48 org.apache.commons.logging.LogFactory.getLog( SmapUtil.class ); 49 50 53 public static final String SMAP_ENCODING = "UTF-8"; 54 55 58 66 public static String [] generateSmap( 67 JspCompilationContext ctxt, 68 Node.Nodes pageNodes) 69 throws IOException { 70 71 PreScanVisitor psVisitor = new PreScanVisitor(); 73 try { 74 pageNodes.visit(psVisitor); 75 } catch (JasperException ex) { 76 } 77 HashMap map = psVisitor.getMap(); 78 79 SmapGenerator g = new SmapGenerator(); 81 82 97 98 SmapStratum s = new SmapStratum("JSP"); 100 101 g.setOutputFileName(unqualify(ctxt.getServletJavaFileName())); 102 103 evaluateNodes(pageNodes, s, map, ctxt.getOptions().getMappedFile()); 105 s.optimizeLineSection(); 106 g.addStratum(s, true); 107 108 if (ctxt.getOptions().isSmapDumped()) { 109 File outSmap = new File (ctxt.getClassFileName() + ".smap"); 110 PrintWriter so = 111 new PrintWriter ( 112 new OutputStreamWriter ( 113 new FileOutputStream (outSmap), 114 SMAP_ENCODING)); 115 so.print(g.getString()); 116 so.close(); 117 } 118 119 String classFileName = ctxt.getClassFileName(); 120 int innerClassCount = map.size(); 121 String [] smapInfo = new String [2 + innerClassCount*2]; 122 smapInfo[0] = classFileName; 123 smapInfo[1] = g.getString(); 124 125 int count = 2; 126 Iterator iter = map.entrySet().iterator(); 127 while (iter.hasNext()) { 128 Map.Entry entry = (Map.Entry ) iter.next(); 129 String innerClass = (String ) entry.getKey(); 130 s = (SmapStratum) entry.getValue(); 131 s.optimizeLineSection(); 132 g = new SmapGenerator(); 133 g.setOutputFileName(unqualify(ctxt.getServletJavaFileName())); 134 g.addStratum(s, true); 135 136 String innerClassFileName = 137 classFileName.substring(0, classFileName.indexOf(".class")) + 138 '$' + innerClass + ".class"; 139 if (ctxt.getOptions().isSmapDumped()) { 140 File outSmap = new File (innerClassFileName + ".smap"); 141 PrintWriter so = 142 new PrintWriter ( 143 new OutputStreamWriter ( 144 new FileOutputStream (outSmap), 145 SMAP_ENCODING)); 146 so.print(g.getString()); 147 so.close(); 148 } 149 smapInfo[count] = innerClassFileName; 150 smapInfo[count+1] = g.getString(); 151 count += 2; 152 } 153 154 return smapInfo; 155 } 156 157 public static void installSmap(String [] smap) 158 throws IOException { 159 if (smap == null) { 160 return; 161 } 162 163 for (int i = 0; i < smap.length; i += 2) { 164 File outServlet = new File (smap[i]); 165 SDEInstaller.install(outServlet, smap[i+1].getBytes()); 166 } 167 } 168 169 172 175 private static String unqualify(String path) { 176 path = path.replace('\\', '/'); 177 return path.substring(path.lastIndexOf('/') + 1); 178 } 179 180 184 private static String inputSmapPath(String path) { 185 return path.substring(0, path.lastIndexOf('.') + 1) + "smap"; 186 } 187 188 private static class SDEInstaller { 191 192 private org.apache.commons.logging.Log log= 193 org.apache.commons.logging.LogFactory.getLog( SDEInstaller.class ); 194 195 static final String nameSDE = "SourceDebugExtension"; 196 197 byte[] orig; 198 byte[] sdeAttr; 199 byte[] gen; 200 201 int origPos = 0; 202 int genPos = 0; 203 204 int sdeIndex; 205 206 public static void main(String [] args) throws IOException { 207 if (args.length == 2) { 208 install(new File (args[0]), new File (args[1])); 209 } else if (args.length == 3) { 210 install( 211 new File (args[0]), 212 new File (args[1]), 213 new File (args[2])); 214 } else { 215 System.err.println( 216 "Usage: <command> <input class file> " 217 + "<attribute file> <output class file name>\n" 218 + "<command> <input/output class file> <attribute file>"); 219 } 220 } 221 222 static void install(File inClassFile, File attrFile, File outClassFile) 223 throws IOException { 224 new SDEInstaller(inClassFile, attrFile, outClassFile); 225 } 226 227 static void install(File inOutClassFile, File attrFile) 228 throws IOException { 229 File tmpFile = new File (inOutClassFile.getPath() + "tmp"); 230 new SDEInstaller(inOutClassFile, attrFile, tmpFile); 231 if (!inOutClassFile.delete()) { 232 throw new IOException ("inOutClassFile.delete() failed"); 233 } 234 if (!tmpFile.renameTo(inOutClassFile)) { 235 throw new IOException ("tmpFile.renameTo(inOutClassFile) failed"); 236 } 237 } 238 239 static void install(File classFile, byte[] smap) throws IOException { 240 File tmpFile = new File (classFile.getPath() + "tmp"); 241 new SDEInstaller(classFile, smap, tmpFile); 242 if (!classFile.delete()) { 243 throw new IOException ("classFile.delete() failed"); 244 } 245 if (!tmpFile.renameTo(classFile)) { 246 throw new IOException ("tmpFile.renameTo(classFile) failed"); 247 } 248 } 249 250 SDEInstaller(File inClassFile, byte[] sdeAttr, File outClassFile) 251 throws IOException { 252 if (!inClassFile.exists()) { 253 throw new FileNotFoundException ("no such file: " + inClassFile); 254 } 255 256 this.sdeAttr = sdeAttr; 257 orig = readWhole(inClassFile); 259 gen = new byte[orig.length + sdeAttr.length + 100]; 260 261 addSDE(); 263 264 FileOutputStream outStream = new FileOutputStream (outClassFile); 266 outStream.write(gen, 0, genPos); 267 outStream.close(); 268 } 269 270 SDEInstaller(File inClassFile, File attrFile, File outClassFile) 271 throws IOException { 272 this(inClassFile, readWhole(attrFile), outClassFile); 273 } 274 275 static byte[] readWhole(File input) throws IOException { 276 FileInputStream inStream = new FileInputStream (input); 277 int len = (int)input.length(); 278 byte[] bytes = new byte[len]; 279 if (inStream.read(bytes, 0, len) != len) { 280 throw new IOException ("expected size: " + len); 281 } 282 inStream.close(); 283 return bytes; 284 } 285 286 void addSDE() throws UnsupportedEncodingException , IOException { 287 int i; 288 copy(4 + 2 + 2); int constantPoolCountPos = genPos; 290 int constantPoolCount = readU2(); 291 if (log.isDebugEnabled()) 292 log.debug("constant pool count: " + constantPoolCount); 293 writeU2(constantPoolCount); 294 295 sdeIndex = copyConstantPool(constantPoolCount); 297 if (sdeIndex < 0) { 298 writeUtf8ForSDE(); 300 301 sdeIndex = constantPoolCount; 303 ++constantPoolCount; 304 randomAccessWriteU2(constantPoolCountPos, constantPoolCount); 305 306 if (log.isDebugEnabled()) 307 log.debug("SourceDebugExtension not found, installed at: " + sdeIndex); 308 } else { 309 if (log.isDebugEnabled()) 310 log.debug("SourceDebugExtension found at: " + sdeIndex); 311 } 312 copy(2 + 2 + 2); int interfaceCount = readU2(); 314 writeU2(interfaceCount); 315 if (log.isDebugEnabled()) 316 log.debug("interfaceCount: " + interfaceCount); 317 copy(interfaceCount * 2); 318 copyMembers(); copyMembers(); int attrCountPos = genPos; 321 int attrCount = readU2(); 322 writeU2(attrCount); 323 if (log.isDebugEnabled()) 324 log.debug("class attrCount: " + attrCount); 325 if (!copyAttrs(attrCount)) { 327 ++attrCount; 329 randomAccessWriteU2(attrCountPos, attrCount); 330 if (log.isDebugEnabled()) 331 log.debug("class attrCount incremented"); 332 } 333 writeAttrForSDE(sdeIndex); 334 } 335 336 void copyMembers() { 337 int count = readU2(); 338 writeU2(count); 339 if (log.isDebugEnabled()) 340 log.debug("members count: " + count); 341 for (int i = 0; i < count; ++i) { 342 copy(6); int attrCount = readU2(); 344 writeU2(attrCount); 345 if (log.isDebugEnabled()) 346 log.debug("member attr count: " + attrCount); 347 copyAttrs(attrCount); 348 } 349 } 350 351 boolean copyAttrs(int attrCount) { 352 boolean sdeFound = false; 353 for (int i = 0; i < attrCount; ++i) { 354 int nameIndex = readU2(); 355 if (nameIndex == sdeIndex) { 357 sdeFound = true; 358 if (log.isDebugEnabled()) 359 log.debug("SDE attr found"); 360 } else { 361 writeU2(nameIndex); int len = readU4(); 363 writeU4(len); 364 copy(len); 365 if (log.isDebugEnabled()) 366 log.debug("attr len: " + len); 367 } 368 } 369 return sdeFound; 370 } 371 372 void writeAttrForSDE(int index) { 373 writeU2(index); 374 writeU4(sdeAttr.length); 375 for (int i = 0; i < sdeAttr.length; ++i) { 376 writeU1(sdeAttr[i]); 377 } 378 } 379 380 void randomAccessWriteU2(int pos, int val) { 381 int savePos = genPos; 382 genPos = pos; 383 writeU2(val); 384 genPos = savePos; 385 } 386 387 int readU1() { 388 return ((int)orig[origPos++]) & 0xFF; 389 } 390 391 int readU2() { 392 int res = readU1(); 393 return (res << 8) + readU1(); 394 } 395 396 int readU4() { 397 int res = readU2(); 398 return (res << 16) + readU2(); 399 } 400 401 void writeU1(int val) { 402 gen[genPos++] = (byte)val; 403 } 404 405 void writeU2(int val) { 406 writeU1(val >> 8); 407 writeU1(val & 0xFF); 408 } 409 410 void writeU4(int val) { 411 writeU2(val >> 16); 412 writeU2(val & 0xFFFF); 413 } 414 415 void copy(int count) { 416 for (int i = 0; i < count; ++i) { 417 gen[genPos++] = orig[origPos++]; 418 } 419 } 420 421 byte[] readBytes(int count) { 422 byte[] bytes = new byte[count]; 423 for (int i = 0; i < count; ++i) { 424 bytes[i] = orig[origPos++]; 425 } 426 return bytes; 427 } 428 429 void writeBytes(byte[] bytes) { 430 for (int i = 0; i < bytes.length; ++i) { 431 gen[genPos++] = bytes[i]; 432 } 433 } 434 435 int copyConstantPool(int constantPoolCount) 436 throws UnsupportedEncodingException , IOException { 437 int sdeIndex = -1; 438 for (int i = 1; i < constantPoolCount; ++i) { 440 int tag = readU1(); 441 writeU1(tag); 442 switch (tag) { 443 case 7 : case 8 : if (log.isDebugEnabled()) 446 log.debug(i + " copying 2 bytes"); 447 copy(2); 448 break; 449 case 9 : case 10 : case 11 : case 3 : case 4 : case 12 : if (log.isDebugEnabled()) 456 log.debug(i + " copying 4 bytes"); 457 copy(4); 458 break; 459 case 5 : case 6 : if (log.isDebugEnabled()) 462 log.debug(i + " copying 8 bytes"); 463 copy(8); 464 i++; 465 break; 466 case 1 : int len = readU2(); 468 writeU2(len); 469 byte[] utf8 = readBytes(len); 470 String str = new String (utf8, "UTF-8"); 471 if (log.isDebugEnabled()) 472 log.debug(i + " read class attr -- '" + str + "'"); 473 if (str.equals(nameSDE)) { 474 sdeIndex = i; 475 } 476 writeBytes(utf8); 477 break; 478 default : 479 throw new IOException ("unexpected tag: " + tag); 480 } 481 } 482 return sdeIndex; 483 } 484 485 void writeUtf8ForSDE() { 486 int len = nameSDE.length(); 487 writeU1(1); writeU2(len); 489 for (int i = 0; i < len; ++i) { 490 writeU1(nameSDE.charAt(i)); 491 } 492 } 493 } 494 495 public static void evaluateNodes( 496 Node.Nodes nodes, 497 SmapStratum s, 498 HashMap innerClassMap, 499 boolean breakAtLF) { 500 try { 501 nodes.visit(new SmapGenVisitor(s, breakAtLF, innerClassMap)); 502 } catch (JasperException ex) { 503 } 504 } 505 506 static class SmapGenVisitor extends Node.Visitor { 507 508 private SmapStratum smap; 509 private boolean breakAtLF; 510 private HashMap innerClassMap; 511 512 SmapGenVisitor(SmapStratum s, boolean breakAtLF, HashMap map) { 513 this.smap = s; 514 this.breakAtLF = breakAtLF; 515 this.innerClassMap = map; 516 } 517 518 public void visitBody(Node n) throws JasperException { 519 SmapStratum smapSave = smap; 520 String innerClass = n.getInnerClassName(); 521 if (innerClass != null) { 522 this.smap = (SmapStratum) innerClassMap.get(innerClass); 523 } 524 super.visitBody(n); 525 smap = smapSave; 526 } 527 528 public void visit(Node.Declaration n) throws JasperException { 529 doSmapText(n); 530 } 531 532 public void visit(Node.Expression n) throws JasperException { 533 doSmapText(n); 534 } 535 536 public void visit(Node.Scriptlet n) throws JasperException { 537 doSmapText(n); 538 } 539 540 public void visit(Node.IncludeAction n) throws JasperException { 541 doSmap(n); 542 visitBody(n); 543 } 544 545 public void visit(Node.ForwardAction n) throws JasperException { 546 doSmap(n); 547 visitBody(n); 548 } 549 550 public void visit(Node.GetProperty n) throws JasperException { 551 doSmap(n); 552 visitBody(n); 553 } 554 555 public void visit(Node.SetProperty n) throws JasperException { 556 doSmap(n); 557 visitBody(n); 558 } 559 560 public void visit(Node.UseBean n) throws JasperException { 561 doSmap(n); 562 visitBody(n); 563 } 564 565 public void visit(Node.PlugIn n) throws JasperException { 566 doSmap(n); 567 visitBody(n); 568 } 569 570 public void visit(Node.CustomTag n) throws JasperException { 571 doSmap(n); 572 visitBody(n); 573 } 574 575 public void visit(Node.UninterpretedTag n) throws JasperException { 576 doSmap(n); 577 visitBody(n); 578 } 579 580 public void visit(Node.JspElement n) throws JasperException { 581 doSmap(n); 582 visitBody(n); 583 } 584 585 public void visit(Node.JspText n) throws JasperException { 586 doSmap(n); 587 visitBody(n); 588 } 589 590 public void visit(Node.NamedAttribute n) throws JasperException { 591 visitBody(n); 592 } 593 594 public void visit(Node.JspBody n) throws JasperException { 595 doSmap(n); 596 visitBody(n); 597 } 598 599 public void visit(Node.InvokeAction n) throws JasperException { 600 doSmap(n); 601 visitBody(n); 602 } 603 604 public void visit(Node.DoBodyAction n) throws JasperException { 605 doSmap(n); 606 visitBody(n); 607 } 608 609 public void visit(Node.ELExpression n) throws JasperException { 610 doSmap(n); 611 } 612 613 public void visit(Node.TemplateText n) throws JasperException { 614 Mark mark = n.getStart(); 615 if (mark == null) { 616 return; 617 } 618 619 String fileName = mark.getFile(); 621 smap.addFile(unqualify(fileName), fileName); 622 623 int iInputStartLine = mark.getLineNumber(); 625 int iOutputStartLine = n.getBeginJavaLine(); 626 int iOutputLineIncrement = breakAtLF? 1: 0; 627 smap.addLineData(iInputStartLine, fileName, 1, iOutputStartLine, 628 iOutputLineIncrement); 629 630 java.util.ArrayList extraSmap = n.getExtraSmap(); 632 633 if (extraSmap != null) { 634 for (int i = 0; i < extraSmap.size(); i++) { 635 iOutputStartLine += iOutputLineIncrement; 636 smap.addLineData( 637 iInputStartLine+((Integer )extraSmap.get(i)).intValue(), 638 fileName, 639 1, 640 iOutputStartLine, 641 iOutputLineIncrement); 642 } 643 } 644 } 645 646 private void doSmap( 647 Node n, 648 int inLineCount, 649 int outIncrement, 650 int skippedLines) { 651 Mark mark = n.getStart(); 652 if (mark == null) { 653 return; 654 } 655 656 String unqualifiedName = unqualify(mark.getFile()); 657 smap.addFile(unqualifiedName, mark.getFile()); 658 smap.addLineData( 659 mark.getLineNumber() + skippedLines, 660 mark.getFile(), 661 inLineCount - skippedLines, 662 n.getBeginJavaLine() + skippedLines, 663 outIncrement); 664 } 665 666 private void doSmap(Node n) { 667 doSmap(n, 1, n.getEndJavaLine() - n.getBeginJavaLine(), 0); 668 } 669 670 private void doSmapText(Node n) { 671 String text = n.getText(); 672 int index = 0; 673 int next = 0; 674 int lineCount = 1; 675 int skippedLines = 0; 676 boolean slashStarSeen = false; 677 boolean beginning = true; 678 679 while ((next = text.indexOf('\n', index)) > -1) { 682 if (beginning) { 683 String line = text.substring(index, next).trim(); 684 if (!slashStarSeen && line.startsWith("/*")) { 685 slashStarSeen = true; 686 } 687 if (slashStarSeen) { 688 skippedLines++; 689 int endIndex = line.indexOf("*/"); 690 if (endIndex >= 0) { 691 slashStarSeen = false; 693 if (endIndex < line.length() - 2) { 694 skippedLines--; 696 beginning = false; 697 } 698 } 699 } else if (line.length() == 0 || line.startsWith("//")) { 700 skippedLines++; 701 } else { 702 beginning = false; 703 } 704 } 705 lineCount++; 706 index = next + 1; 707 } 708 709 doSmap(n, lineCount, 1, skippedLines); 710 } 711 } 712 713 private static class PreScanVisitor extends Node.Visitor { 714 715 HashMap map = new HashMap (); 716 717 public void doVisit(Node n) { 718 String inner = n.getInnerClassName(); 719 if (inner != null && !map.containsKey(inner)) { 720 map.put(inner, new SmapStratum("JSP")); 721 } 722 } 723 724 HashMap getMap() { 725 return map; 726 } 727 } 728 729 } 730 | Popular Tags |