1 52 53 package freemarker.ext.jsp; 54 55 import java.beans.BeanInfo ; 56 import java.beans.IntrospectionException ; 57 import java.beans.Introspector ; 58 import java.beans.PropertyDescriptor ; 59 import java.io.CharArrayReader ; 60 import java.io.CharArrayWriter ; 61 import java.io.IOException ; 62 import java.io.Reader ; 63 import java.io.Writer ; 64 import java.lang.reflect.InvocationTargetException ; 65 import java.lang.reflect.Method ; 66 import java.util.HashMap ; 67 import java.util.Iterator ; 68 import java.util.Map ; 69 70 import javax.servlet.jsp.JspException ; 71 import javax.servlet.jsp.JspWriter ; 72 import javax.servlet.jsp.tagext.BodyContent ; 73 import javax.servlet.jsp.tagext.BodyTag ; 74 import javax.servlet.jsp.tagext.IterationTag ; 75 import javax.servlet.jsp.tagext.Tag ; 76 import javax.servlet.jsp.tagext.TryCatchFinally ; 77 78 import freemarker.ext.beans.BeansWrapper; 79 import freemarker.log.Logger; 80 import freemarker.template.ObjectWrapper; 81 import freemarker.template.TemplateModel; 82 import freemarker.template.TemplateModelException; 83 import freemarker.template.TemplateTransformModel; 84 import freemarker.template.TransformControl; 85 import freemarker.template.utility.SecurityUtilities; 86 import freemarker.template.utility.StringUtil; 87 88 92 class TagTransformModel implements TemplateTransformModel 93 { 94 private static final char[] NEWLINE = SecurityUtilities.getSystemProperty("line.separator").toCharArray(); 95 96 private static final Logger logger = Logger.getLogger("freemarker.servlet"); 97 98 private final Class tagClass; 99 private final Map propertySetters = new HashMap (); 100 private final boolean isBodyTag; 101 private final boolean isIterationTag; 102 private final boolean isTryCatchFinally; 103 104 public TagTransformModel(Class tagClass) 105 throws 106 IntrospectionException 107 { 108 if(!Tag .class.isAssignableFrom(tagClass)) { 109 throw new IllegalArgumentException (tagClass.getName() + " does not implement the " + Tag .class.getName() + " interface."); 110 } 111 isIterationTag = IterationTag .class.isAssignableFrom(tagClass); 112 isBodyTag = isIterationTag && BodyTag .class.isAssignableFrom(tagClass); 113 isTryCatchFinally = TryCatchFinally .class.isAssignableFrom(tagClass); 114 115 this.tagClass = tagClass; 116 BeanInfo bi = Introspector.getBeanInfo(tagClass); 117 PropertyDescriptor [] pda = bi.getPropertyDescriptors(); 118 for (int i = 0; i < pda.length; i++) 119 { 120 PropertyDescriptor pd = pda[i]; 121 Method m = pd.getWriteMethod(); 122 if(m != null) 123 { 124 propertySetters.put(pd.getName(), m); 125 } 126 } 127 } 128 129 public Writer getWriter(Writer out, Map args) throws TemplateModelException 130 { 131 try { 132 Tag tag = getTagInstance(); 133 FreeMarkerPageContext pageContext = FreeMarkerPageContext.getCurrentPageContext(); 134 Tag parentTag = pageContext.peekTopTag(); 135 tag.setParent(parentTag); 136 tag.setPageContext(pageContext); 137 setupTag(tag, args, pageContext.getObjectWrapper()); 138 boolean usesAdapter; 141 if(out instanceof JspWriter ) { 142 if(out != pageContext.getOut()) { 145 throw new TemplateModelException( 146 "out != pageContext.getOut(). Out is " + 147 out + " pageContext.getOut() is " + 148 pageContext.getOut()); 149 } 150 usesAdapter = false; 151 } 152 else { 153 out = new JspWriterAdapter(out); 154 pageContext.pushWriter((JspWriter )out); 155 usesAdapter = true; 156 } 157 JspWriter w = new TagWriter(out, tag, pageContext, usesAdapter); 158 pageContext.pushTopTag(tag); 159 pageContext.pushWriter(w); 160 return w; 161 } 162 catch(TemplateModelException e) { 163 throw e; 164 } 165 catch(Exception e) { 166 throw new TemplateModelException(e); 167 } 168 } 169 170 private Tag getTagInstance() 171 throws 172 IllegalAccessException , 173 InstantiationException 174 { 175 return (Tag )tagClass.newInstance(); 176 } 177 178 private void setupTag(Object tag, Map args, ObjectWrapper wrapper) 179 throws 180 TemplateModelException, 181 InvocationTargetException , 182 IllegalAccessException 183 { 184 BeansWrapper bwrapper = 185 wrapper instanceof BeansWrapper 186 ? (BeansWrapper)wrapper 187 : BeansWrapper.getDefaultInstance(); 188 if(args != null && !args.isEmpty()) 189 { 190 Object [] aarg = new Object [1]; 191 for (Iterator iter = args.entrySet().iterator(); iter.hasNext();) 192 { 193 Map.Entry entry = (Map.Entry ) iter.next(); 194 aarg[0] = bwrapper.unwrap((TemplateModel)entry.getValue()); 195 Method m = (Method )propertySetters.get(entry.getKey()); 196 if(m == null) 197 { 198 throw new TemplateModelException("Unknown property " 199 + StringUtil.jQuote(entry.getKey().toString()) 200 + " on instance of " + tagClass.getName()); 201 } 202 BeansWrapper.coerceBigDecimals(m, aarg); 203 m.invoke(tag, aarg); 204 } 205 } 206 } 207 208 private class TagWriter extends BodyContent implements TransformControl 209 { 210 private final Tag tag; 211 private final FreeMarkerPageContext pageContext; 212 private CharArrayWriter buf; 213 private boolean needPop = true; 214 private final boolean needDoublePop; 215 216 TagWriter(Writer out, Tag tag, FreeMarkerPageContext pageContext, boolean needDoublePop) 217 { 218 super((JspWriter )out); 219 this.needDoublePop = needDoublePop; 220 this.tag = tag; 221 this.pageContext = pageContext; 222 } 223 224 public String toString() { 225 return "TagWriter for " + tag.getClass().getName() + " wrapping a " + getEnclosingWriter().toString(); 226 } 227 228 Tag getTag() 229 { 230 return tag; 231 } 232 233 FreeMarkerPageContext getPageContext() 234 { 235 return pageContext; 236 } 237 238 public int onStart() 239 throws 240 TemplateModelException 241 { 242 try { 243 int dst = tag.doStartTag(); 244 switch(dst) { 245 case Tag.SKIP_BODY: 246 case Tag.EVAL_PAGE: { 252 endEvaluation(); 253 return TransformControl.SKIP_BODY; 254 } 255 case BodyTag.EVAL_BODY_BUFFERED: { 256 if(isBodyTag) { 257 BodyTag btag = (BodyTag )tag; 258 buf = new CharArrayWriter (); 259 btag.setBodyContent(this); 260 btag.doInitBody(); 261 } 262 else { 263 throw new TemplateModelException("Can't buffer body since " + tag.getClass().getName() + " does not implement BodyTag."); 264 } 265 } 267 case Tag.EVAL_BODY_INCLUDE: { 268 return TransformControl.EVALUATE_BODY; 269 } 270 default: { 271 throw new RuntimeException ("Illegal return value " + dst + " from " + tag.getClass().getName() + ".doStartTag()"); 272 } 273 } 274 } 275 catch(JspException e) { 276 throw new TemplateModelException(e.getMessage(), e); 277 } 278 } 279 280 public int afterBody() 281 throws 282 TemplateModelException 283 { 284 try { 285 if(isIterationTag) { 286 int dab = ((IterationTag )tag).doAfterBody(); 287 switch(dab) { 288 case Tag.SKIP_BODY: { 289 endEvaluation(); 290 return END_EVALUATION; 291 } 292 case IterationTag.EVAL_BODY_AGAIN: { 293 return REPEAT_EVALUATION; 294 } 295 default: { 296 throw new TemplateModelException("Unexpected return value " + dab + "from " + tag.getClass().getName() + ".doAfterBody()"); 297 } 298 } 299 } 300 endEvaluation(); 301 return END_EVALUATION; 302 } 303 catch(JspException e) { 304 throw new TemplateModelException(e); 305 } 306 } 307 308 private void endEvaluation() throws JspException { 309 if(needPop) { 310 pageContext.popWriter(); 311 needPop = false; 312 } 313 if(tag.doEndTag() == Tag.SKIP_PAGE) { 314 logger.warn("Tag.SKIP_PAGE was ignored from a " + tag.getClass().getName() + " tag."); 315 } 316 } 317 318 public void onError(Throwable t) throws Throwable { 319 if(isTryCatchFinally) { 320 ((TryCatchFinally )tag).doCatch(t); 321 } 322 else { 323 throw t; 324 } 325 } 326 327 public void close() { 328 if(needPop) { 329 pageContext.popWriter(); 330 } 331 pageContext.popTopTag(); 332 try { 333 if(isTryCatchFinally) { 334 ((TryCatchFinally )tag).doFinally(); 335 } 336 tag.release(); 338 } 339 finally { 340 if(needDoublePop) { 341 pageContext.popWriter(); 342 } 343 } 344 } 345 346 public void flush() throws IOException { 347 if(buf == null) { 348 getEnclosingWriter().flush(); 349 } 350 } 351 352 public void clear() throws IOException { 353 if(buf != null) { 354 buf = new CharArrayWriter (); 355 } 356 else { 357 throw new IOException ("Can't clear"); 358 } 359 } 360 361 public void clearBuffer() throws IOException { 362 if(buf != null) { 363 buf = new CharArrayWriter (); 364 } 365 else { 366 throw new IOException ("Can't clear"); 367 } 368 } 369 370 public int getRemaining() { 371 return Integer.MAX_VALUE; 372 } 373 374 public void newLine() throws IOException { 375 write(NEWLINE); 376 } 377 378 public void print(boolean arg0) throws IOException { 379 write(arg0 ? Boolean.TRUE.toString() : Boolean.FALSE.toString()); 380 } 381 382 public void print(char arg0) throws IOException 383 { 384 write(arg0); 385 } 386 387 public void print(char[] arg0) throws IOException 388 { 389 write(arg0); 390 } 391 392 public void print(double arg0) throws IOException 393 { 394 write(Double.toString(arg0)); 395 } 396 397 public void print(float arg0) throws IOException 398 { 399 write(Float.toString(arg0)); 400 } 401 402 public void print(int arg0) throws IOException 403 { 404 write(Integer.toString(arg0)); 405 } 406 407 public void print(long arg0) throws IOException 408 { 409 write(Long.toString(arg0)); 410 } 411 412 public void print(Object arg0) throws IOException 413 { 414 write(arg0 == null ? "null" : arg0.toString()); 415 } 416 417 public void print(String arg0) throws IOException 418 { 419 write(arg0); 420 } 421 422 public void println() throws IOException 423 { 424 newLine(); 425 } 426 427 public void println(boolean arg0) throws IOException 428 { 429 print(arg0); 430 newLine(); 431 } 432 433 public void println(char arg0) throws IOException 434 { 435 print(arg0); 436 newLine(); 437 } 438 439 public void println(char[] arg0) throws IOException 440 { 441 print(arg0); 442 newLine(); 443 } 444 445 public void println(double arg0) throws IOException 446 { 447 print(arg0); 448 newLine(); 449 } 450 451 public void println(float arg0) throws IOException 452 { 453 print(arg0); 454 newLine(); 455 } 456 457 public void println(int arg0) throws IOException 458 { 459 print(arg0); 460 newLine(); 461 } 462 463 public void println(long arg0) throws IOException 464 { 465 print(arg0); 466 newLine(); 467 } 468 469 public void println(Object arg0) throws IOException 470 { 471 print(arg0); 472 newLine(); 473 } 474 475 public void println(String arg0) throws IOException 476 { 477 print(arg0); 478 newLine(); 479 } 480 481 public void write(int c) throws IOException 482 { 483 if(buf != null) { 484 buf.write(c); 485 } 486 else { 487 getEnclosingWriter().write(c); 488 } 489 } 490 491 public void write(char[] cbuf, int off, int len) throws IOException 492 { 493 if(buf != null) { 494 buf.write(cbuf, off, len); 495 } 496 else { 497 getEnclosingWriter().write(cbuf, off, len); 498 } 499 } 500 501 public String getString() { 502 return buf.toString(); 503 } 504 505 public Reader getReader() { 506 return new CharArrayReader (buf.toCharArray()); 507 } 508 509 public void writeOut(Writer out) throws IOException { 510 buf.writeTo(out); 511 } 512 } 513 514 static class JspWriterAdapter extends JspWriter { 515 private final Writer out; 516 517 JspWriterAdapter(Writer out) { 518 super(0, true); 519 this.out = out; 520 } 521 522 public String toString() { 523 return "JspWriterAdapter wrapping a " + out.toString(); 524 } 525 526 public void clear() throws IOException { 527 throw new IOException ("Can't clear"); 528 } 529 530 public void clearBuffer() throws IOException { 531 throw new IOException ("Can't clear"); 532 } 533 534 public void close() throws IOException { 535 throw new IOException ("Close not permitted."); 536 } 537 538 public void flush() throws IOException { 539 out.flush(); 540 } 541 542 public int getRemaining() { 543 return 0; 544 } 545 546 public void newLine() throws IOException { 547 out.write(NEWLINE); 548 } 549 550 public void print(boolean arg0) throws IOException { 551 out.write(arg0 ? Boolean.TRUE.toString() : Boolean.FALSE.toString()); 552 } 553 554 public void print(char arg0) throws IOException 555 { 556 out.write(arg0); 557 } 558 559 public void print(char[] arg0) throws IOException 560 { 561 out.write(arg0); 562 } 563 564 public void print(double arg0) throws IOException 565 { 566 out.write(Double.toString(arg0)); 567 } 568 569 public void print(float arg0) throws IOException 570 { 571 out.write(Float.toString(arg0)); 572 } 573 574 public void print(int arg0) throws IOException 575 { 576 out.write(Integer.toString(arg0)); 577 } 578 579 public void print(long arg0) throws IOException 580 { 581 out.write(Long.toString(arg0)); 582 } 583 584 public void print(Object arg0) throws IOException 585 { 586 out.write(arg0 == null ? "null" : arg0.toString()); 587 } 588 589 public void print(String arg0) throws IOException 590 { 591 out.write(arg0); 592 } 593 594 public void println() throws IOException 595 { 596 newLine(); 597 } 598 599 public void println(boolean arg0) throws IOException 600 { 601 print(arg0); 602 newLine(); 603 } 604 605 public void println(char arg0) throws IOException 606 { 607 print(arg0); 608 newLine(); 609 } 610 611 public void println(char[] arg0) throws IOException 612 { 613 print(arg0); 614 newLine(); 615 } 616 617 public void println(double arg0) throws IOException 618 { 619 print(arg0); 620 newLine(); 621 } 622 623 public void println(float arg0) throws IOException 624 { 625 print(arg0); 626 newLine(); 627 } 628 629 public void println(int arg0) throws IOException 630 { 631 print(arg0); 632 newLine(); 633 } 634 635 public void println(long arg0) throws IOException 636 { 637 print(arg0); 638 newLine(); 639 } 640 641 public void println(Object arg0) throws IOException 642 { 643 print(arg0); 644 newLine(); 645 } 646 647 public void println(String arg0) throws IOException 648 { 649 print(arg0); 650 newLine(); 651 } 652 653 public void write(int c) throws IOException 654 { 655 out.write(c); 656 } 657 658 public void write(char[] arg0, int arg1, int arg2) 659 throws IOException 660 { 661 out.write(arg0, arg1, arg2); 662 } 663 } 664 } 665 | Popular Tags |