1 29 30 package com.caucho.jsp; 31 32 import com.caucho.bytecode.ByteCodeParser; 33 import com.caucho.bytecode.CodeAttribute; 34 import com.caucho.bytecode.CodeVisitor; 35 import com.caucho.bytecode.JavaClass; 36 import com.caucho.bytecode.JavaMethod; 37 import com.caucho.log.Log; 38 import com.caucho.util.L10N; 39 40 import javax.annotation.Resource; 41 import javax.ejb.EJB ; 42 import javax.servlet.jsp.tagext.*; 43 import javax.xml.ws.WebServiceRef; 44 import java.io.InputStream ; 45 import java.lang.reflect.Field ; 46 import java.lang.reflect.Method ; 47 import java.util.HashMap ; 48 import java.util.logging.Level ; 49 import java.util.logging.Logger ; 50 51 66 public class TagAnalyzer { 67 private static final Logger log = Log.open(TagAnalyzer.class); 68 static final L10N L = new L10N(TagAnalyzer.class); 69 70 private HashMap <Class ,AnalyzedTag> _analyzedTags = 71 new HashMap <Class ,AnalyzedTag>(); 72 73 76 public AnalyzedTag analyze(Class tagClass) 77 { 78 if (tagClass == null) 79 return null; 80 81 AnalyzedTag analyzedTag = _analyzedTags.get(tagClass); 82 if (analyzedTag != null) 83 return analyzedTag; 84 85 if (! JspTag.class.isAssignableFrom(tagClass)) { 86 return null; 87 } 88 89 if (tagClass.isInterface()) { 90 return null; 91 } 92 93 AnalyzedTag parent = analyze(tagClass.getSuperclass()); 94 95 String name = tagClass.getName().replace('.', '/') + ".class"; 96 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 97 98 AnalyzedTag tag = new AnalyzedTag(); 99 100 try { 101 analyzeByReflection(tagClass, tag, parent); 102 103 InputStream is = loader.getResourceAsStream(name); 104 105 if (is == null) 106 return tag; 107 108 try { 109 JavaClass javaClass = new ByteCodeParser().parse(is); 110 111 analyze(javaClass, "doStartTag", "()I", new StartAnalyzer(), tag); 112 analyze(javaClass, "doEndTag", "()I", new EndAnalyzer(), tag); 113 114 if (IterationTag.class.isAssignableFrom(tagClass)) { 115 analyze(javaClass, "doAfterBody", "()I", new AfterAnalyzer(), tag); 116 } 117 118 if (BodyTag.class.isAssignableFrom(tagClass)) { 119 analyze(javaClass, "doInitBody", "()V", 120 new InitAnalyzer(), tag); 121 } 122 123 if (TryCatchFinally.class.isAssignableFrom(tagClass)) { 124 analyze(javaClass, "doCatch", "(Ljava/lang/Throwable;)V", 125 new CatchAnalyzer(), tag); 126 analyze(javaClass, "doFinally", "()V", 127 new FinallyAnalyzer(), tag); 128 } 129 } finally { 130 is.close(); 131 } 132 } catch (Exception e) { 133 log.log(Level.WARNING, e.toString(), e); 134 } 135 136 return tag; 137 } 138 139 142 public void analyzeByReflection(Class tagClass, 143 AnalyzedTag tag, AnalyzedTag parent) 144 { 145 tag.setBodyTag(BodyTag.class.isAssignableFrom(tagClass)); 146 147 Method doStartMethod = getMethod(tagClass, "doStartTag", new Class [0]); 148 149 if (doStartMethod != null && 150 doStartMethod.getDeclaringClass().equals(tagClass)) { 151 if (TagSupport.class.equals(tagClass)) { 152 tag.setDoStart(false); 153 tag.setStartReturnsSkip(false); 154 tag.setStartReturnsInclude(true); 155 tag.setStartReturnsBuffered(false); 156 } 157 else if (BodyTagSupport.class.equals(tagClass)) { 158 tag.setDoStart(false); 159 tag.setStartReturnsSkip(false); 160 tag.setStartReturnsInclude(false); 161 tag.setStartReturnsBuffered(true); 162 } 163 else if (BodyTag.class.isAssignableFrom(tagClass)) { 164 tag.setDoStart(true); 165 tag.setStartReturnsSkip(true); 166 tag.setStartReturnsInclude(true); 167 tag.setStartReturnsBuffered(true); 168 } 169 else { 170 tag.setDoStart(true); 171 tag.setStartReturnsSkip(true); 172 tag.setStartReturnsInclude(true); 173 tag.setStartReturnsBuffered(false); 174 } 175 } 176 else if (parent != null) { 177 tag.setDoStart(parent.getDoStart()); 178 tag.setStartReturnsSkip(parent.getStartReturnsSkip()); 179 tag.setStartReturnsInclude(parent.getStartReturnsInclude()); 180 tag.setStartReturnsBuffered(parent.getStartReturnsBufferedAsParent()); 181 } 182 183 Method doEndMethod = getMethod(tagClass, "doEndTag", new Class [0]); 184 185 if (doEndMethod != null && 186 doEndMethod.getDeclaringClass().equals(tagClass)) { 187 if (TagSupport.class.equals(tagClass) || 188 BodyTagSupport.class.equals(tagClass)) { 189 tag.setDoEnd(false); 190 tag.setEndReturnsSkip(false); 191 tag.setEndReturnsEval(true); 192 } 193 else { 194 tag.setDoEnd(true); 195 tag.setEndReturnsSkip(true); 196 tag.setEndReturnsEval(true); 197 } 198 } 199 else if (parent != null) { 200 tag.setDoEnd(parent.getDoEnd()); 201 tag.setEndReturnsSkip(parent.getEndReturnsSkip()); 202 tag.setEndReturnsEval(parent.getEndReturnsEval()); 203 } 204 205 Method doAfterBody = getMethod(tagClass, "doAfterBody", new Class [0]); 206 207 if (doAfterBody != null && 208 doAfterBody.getDeclaringClass().equals(tagClass)) { 209 if (TagSupport.class.equals(tagClass) || 210 BodyTagSupport.class.equals(tagClass)) { 211 tag.setDoAfter(false); 212 tag.setAfterReturnsAgain(false); 213 } 214 else if (! IterationTag.class.isAssignableFrom(tagClass)) { 215 tag.setDoAfter(false); 216 tag.setAfterReturnsAgain(false); 217 } 218 else { 219 tag.setDoAfter(true); 220 tag.setAfterReturnsAgain(true); 221 } 222 } 223 else if (parent != null) { 224 tag.setDoAfter(parent.getDoAfter()); 225 tag.setAfterReturnsAgain(parent.getAfterReturnsAgain()); 226 } 227 228 Method doInitBody = getMethod(tagClass, "doInitBody", new Class [0]); 229 230 if (doInitBody != null && 231 doInitBody.getDeclaringClass().equals(tagClass)) { 232 if (BodyTagSupport.class.equals(tagClass)) { 233 tag.setDoInit(false); 234 } 235 else if (! BodyTag.class.isAssignableFrom(tagClass)) { 236 tag.setDoInit(false); 237 } 238 else { 239 tag.setDoInit(true); 240 } 241 } 242 else if (parent != null) { 243 tag.setDoInit(parent.getDoInit()); 244 } 245 246 Method doCatch = getMethod(tagClass, "doCatch", 247 new Class [] { Throwable .class }); 248 249 if (doCatch != null && 250 doCatch.getDeclaringClass().equals(tagClass)) { 251 if (! TryCatchFinally.class.isAssignableFrom(tagClass)) { 252 tag.setDoCatch(false); 253 } 254 else { 255 tag.setDoCatch(true); 256 } 257 } 258 else if (parent != null) { 259 tag.setDoCatch(parent.getDoCatch()); 260 } 261 262 Method doFinally = getMethod(tagClass, "doFinally", new Class [0]); 263 264 if (doFinally != null && 265 doFinally.getDeclaringClass().equals(tagClass)) { 266 if (! TryCatchFinally.class.isAssignableFrom(tagClass)) { 267 tag.setDoFinally(false); 268 } 269 else { 270 tag.setDoFinally(true); 271 } 272 } 273 else if (parent != null) { 274 tag.setDoFinally(parent.getDoFinally()); 275 } 276 277 for (Method method : tagClass.getDeclaredMethods()) { 279 if (method.getName().startsWith("set") 280 && (method.isAnnotationPresent(Resource.class) 281 || method.isAnnotationPresent(EJB .class) 282 || method.isAnnotationPresent(WebServiceRef.class))) { 283 tag.setHasInjection(true); 284 } 285 } 286 287 for (Field field : tagClass.getDeclaredFields()) { 288 if (field.isAnnotationPresent(Resource.class) 289 || field.isAnnotationPresent(EJB .class) 290 || field.isAnnotationPresent(WebServiceRef.class)) { 291 tag.setHasInjection(true); 292 } 293 } 294 } 295 296 private Method getMethod(Class tagClass, String name, Class []args) 297 { 298 try { 299 return tagClass.getMethod(name, args); 300 } catch (Throwable e) { 301 return null; 302 } 303 } 304 305 308 private void analyze(JavaClass javaClass, 309 String name, 310 String signature, 311 Analyzer analyzer, 312 AnalyzedTag tag) 313 { 314 JavaMethod method = javaClass.findMethod(name, signature); 315 if (method == null) 316 return; 317 318 CodeAttribute codeAttribute = method.getCode(); 319 320 if (codeAttribute == null) 321 return; 322 323 CodeVisitor visitor = new CodeVisitor(javaClass, codeAttribute); 324 try { 325 visitor.analyze(analyzer); 326 } catch (Exception e) { 327 log.log(Level.WARNING, e.toString(), e); 328 } 329 330 analyzer.complete(tag); 331 } 332 333 static class Analyzer extends com.caucho.bytecode.Analyzer { 334 public void analyze(CodeVisitor visitor) 335 { 336 } 337 338 public void complete(AnalyzedTag tag) 339 { 340 } 341 } 342 343 346 static class StartAnalyzer extends Analyzer { 347 private boolean _hasSkip; 348 private boolean _hasInclude; 349 private boolean _hasBuffered; 350 private boolean _hasStart; 351 352 private int _count = 0; 353 private int _value = -1; 354 355 public void analyze(CodeVisitor visitor) 356 { 357 int count = _count++; 358 359 switch (visitor.getOpcode()) { 360 case CodeVisitor.IRETURN: 361 if (count != 1) 362 _hasStart = true; 363 364 if (_value == Tag.SKIP_BODY) 365 _hasSkip = true; 366 else if (_value == Tag.EVAL_BODY_INCLUDE) 367 _hasInclude = true; 368 else if (_value == BodyTag.EVAL_BODY_BUFFERED) 369 _hasBuffered = true; 370 else { 371 _hasSkip = true; 372 _hasInclude = true; 373 _hasBuffered = true; 374 } 375 break; 376 377 case CodeVisitor.ICONST_M1: 378 case CodeVisitor.ICONST_0: 379 case CodeVisitor.ICONST_1: 380 case CodeVisitor.ICONST_2: 381 case CodeVisitor.ICONST_3: 382 case CodeVisitor.ICONST_4: 383 case CodeVisitor.ICONST_5: 384 if (count != 0) 385 _hasStart = true; 386 387 _value = visitor.getOpcode() - CodeVisitor.ICONST_0; 388 break; 389 390 case CodeVisitor.BIPUSH: 391 if (count != 0) 392 _hasStart = true; 393 _value = visitor.getByteArg(); 394 break; 395 396 case CodeVisitor.SIPUSH: 397 if (count != 0) 398 _hasStart = true; 399 _value = visitor.getShortArg(); 400 break; 401 402 default: 403 _hasStart = true; 404 _value = -1; 405 break; 406 } 407 } 408 409 public void complete(AnalyzedTag tag) 410 { 411 tag.setDoStart(_hasStart); 412 tag.setStartReturnsSkip(_hasSkip); 413 tag.setStartReturnsInclude(_hasInclude); 414 tag.setStartReturnsBuffered(_hasBuffered); 415 } 416 } 417 418 421 static class EndAnalyzer extends Analyzer { 422 private boolean _hasSkip; 423 private boolean _hasEval; 424 private boolean _hasEnd; 425 426 private int _count = 0; 427 private int _value = -1; 428 429 public void analyze(CodeVisitor visitor) 430 { 431 int count = _count++; 432 433 switch (visitor.getOpcode()) { 434 case CodeVisitor.IRETURN: 435 if (count != 1) 436 _hasEnd = true; 437 438 if (_value == Tag.SKIP_PAGE) 439 _hasSkip = true; 440 else if (_value == Tag.EVAL_PAGE) 441 _hasEval = true; 442 else { 443 _hasEnd = true; 444 _hasSkip = true; 445 _hasEval = true; 446 } 447 break; 448 449 case CodeVisitor.ICONST_M1: 450 case CodeVisitor.ICONST_0: 451 case CodeVisitor.ICONST_1: 452 case CodeVisitor.ICONST_2: 453 case CodeVisitor.ICONST_3: 454 case CodeVisitor.ICONST_4: 455 case CodeVisitor.ICONST_5: 456 if (count != 0) 457 _hasEnd = true; 458 459 _value = visitor.getOpcode() - CodeVisitor.ICONST_0; 460 break; 461 462 case CodeVisitor.BIPUSH: 463 if (count != 0) 464 _hasEnd = true; 465 _value = visitor.getByteArg(); 466 break; 467 468 case CodeVisitor.SIPUSH: 469 if (count != 0) 470 _hasEnd = true; 471 _value = visitor.getShortArg(); 472 break; 473 474 default: 475 _hasEnd = true; 476 _value = -1; 477 break; 478 } 479 } 480 481 public void complete(AnalyzedTag tag) 482 { 483 tag.setDoEnd(_hasEnd); 484 tag.setEndReturnsSkip(_hasSkip); 485 tag.setEndReturnsEval(_hasEval); 486 } 487 } 488 489 492 static class AfterAnalyzer extends Analyzer { 493 private boolean _hasAfter; 494 private boolean _hasAgain; 495 496 private int _count = 0; 497 private int _value = -1; 498 499 public void analyze(CodeVisitor visitor) 500 { 501 int count = _count++; 502 503 switch (visitor.getOpcode()) { 504 case CodeVisitor.IRETURN: 505 if (count != 1) 506 _hasAfter = true; 507 508 if (_value == IterationTag.EVAL_BODY_AGAIN) 509 _hasAgain = true; 510 else if (_value == IterationTag.SKIP_BODY) { 511 } 512 else { 513 _hasAgain = true; 514 } 515 break; 516 517 case CodeVisitor.ICONST_M1: 518 case CodeVisitor.ICONST_0: 519 case CodeVisitor.ICONST_1: 520 case CodeVisitor.ICONST_2: 521 case CodeVisitor.ICONST_3: 522 case CodeVisitor.ICONST_4: 523 case CodeVisitor.ICONST_5: 524 if (count != 0) 525 _hasAfter = true; 526 527 _value = visitor.getOpcode() - CodeVisitor.ICONST_0; 528 break; 529 530 case CodeVisitor.BIPUSH: 531 if (count != 0) 532 _hasAfter = true; 533 _value = visitor.getByteArg(); 534 break; 535 536 case CodeVisitor.SIPUSH: 537 if (count != 0) 538 _hasAfter = true; 539 _value = visitor.getShortArg(); 540 break; 541 542 default: 543 _hasAfter = true; 544 _value = -1; 545 break; 546 } 547 } 548 549 public void complete(AnalyzedTag tag) 550 { 551 tag.setDoAfter(_hasAfter); 552 tag.setAfterReturnsAgain(_hasAgain); 553 } 554 } 555 556 559 static class InitAnalyzer extends Analyzer { 560 private boolean _hasCode; 561 562 private int _count = 0; 563 564 public void analyze(CodeVisitor visitor) 565 { 566 int count = _count++; 567 568 switch (visitor.getOpcode()) { 569 case CodeVisitor.RETURN: 570 if (count != 0) 571 _hasCode = true; 572 break; 573 574 default: 575 _hasCode = true; 576 break; 577 } 578 } 579 580 public void complete(AnalyzedTag tag) 581 { 582 tag.setDoInit(_hasCode); 583 } 584 } 585 586 589 static class CatchAnalyzer extends Analyzer { 590 private boolean _hasCode; 591 592 private int _count = 0; 593 594 public void analyze(CodeVisitor visitor) 595 { 596 int count = _count++; 597 598 switch (visitor.getOpcode()) { 599 case CodeVisitor.RETURN: 600 if (count != 0) 601 _hasCode = true; 602 break; 603 604 default: 605 _hasCode = true; 606 break; 607 } 608 } 609 610 public void complete(AnalyzedTag tag) 611 { 612 tag.setDoCatch(_hasCode); 613 } 614 } 615 616 619 static class FinallyAnalyzer extends Analyzer { 620 private boolean _hasCode; 621 622 private int _count = 0; 623 624 public void analyze(CodeVisitor visitor) 625 { 626 int count = _count++; 627 628 switch (visitor.getOpcode()) { 629 case CodeVisitor.RETURN: 630 if (count != 0) 631 _hasCode = true; 632 break; 633 634 default: 635 _hasCode = true; 636 break; 637 } 638 } 639 640 public void complete(AnalyzedTag tag) 641 { 642 tag.setDoFinally(_hasCode); 643 } 644 } 645 } 646 | Popular Tags |