1 29 30 package com.caucho.jsp.java; 31 32 import com.caucho.jsp.JspParseException; 33 import com.caucho.jsp.TagInstance; 34 import com.caucho.util.BeanUtil; 35 import com.caucho.vfs.WriteStream; 36 import com.caucho.xml.QName; 37 38 import javax.servlet.jsp.tagext.*; 39 import java.beans.BeanInfo ; 40 import java.beans.Introspector ; 41 import java.io.IOException ; 42 import java.lang.reflect.Method ; 43 import java.lang.reflect.Modifier ; 44 import java.util.ArrayList ; 45 import java.util.HashSet ; 46 import java.util.Hashtable ; 47 import java.util.logging.Level ; 48 49 52 abstract public class GenericTag extends JspContainerNode 53 { 54 private static final String DEFAULT_VAR_TYPE = "java.lang.String"; 55 56 private static final HashSet <String > _primTypes 57 = new HashSet <String >(); 58 59 protected TagInstance _tag; 60 protected TagInfo _tagInfo; 61 protected Class _tagClass; 62 protected VariableInfo []_varInfo; 63 64 public GenericTag() 65 { 66 } 67 68 public void setTagInfo(TagInfo tagInfo) 69 { 70 _tagInfo = tagInfo; 71 } 72 73 public TagInfo getTagInfo() 74 { 75 return _tagInfo; 76 } 77 78 public TagInstance getTag() 79 { 80 return _tag; 81 } 82 83 86 public String getCustomTagName() 87 { 88 return _tag.getId(); 89 } 90 91 94 public boolean isSimple() 95 { 96 return _tag.isSimpleTag(); 97 } 98 99 public void setTagClass(Class cl) 100 { 101 _tagClass = cl; 102 } 103 104 public VariableInfo []getVarInfo() 105 { 106 return _varInfo; 107 } 108 109 112 public String getBodyContent() 113 { 114 return _tagInfo.getBodyContent(); 115 } 116 117 120 public void addChild(JspNode node) 121 throws JspParseException 122 { 123 if (! "empty".equals(getBodyContent())) 124 super.addChild(node); 125 else if (node instanceof JspAttribute) { 126 super.addChild(node); 127 } 128 else if (node instanceof StaticText && 129 ((StaticText) node).isWhitespace()) { 130 } 131 else { 132 throw error(L.l("<{0}> must be empty. Since <{0}> has a body-content of 'empty', it must not have any content.", 133 getTagName())); 134 } 135 } 136 137 140 public void endElement() 141 throws Exception 142 { 143 if (_tagClass != null) 144 _gen.addDepend(_tagClass); 145 146 Hashtable <String ,Object > tags = new Hashtable <String ,Object >(); 147 148 for (int i = 0; i < _attributeNames.size(); i++) { 149 QName qName = _attributeNames.get(i); 150 Object value = _attributeValues.get(i); 151 String name = qName.getName(); 152 153 if (value instanceof JspAttribute) { 154 JspAttribute attr = (JspAttribute) value; 155 156 if (attr.isStatic()) 157 tags.put(name, attr.getStaticText()); 158 else 159 tags.put(name, TagData.REQUEST_TIME_VALUE); 160 } 161 else if (value instanceof String && hasRuntimeAttribute((String ) value)) 162 tags.put(name, TagData.REQUEST_TIME_VALUE); 163 else 164 tags.put(name, value); 165 166 TagAttributeInfo attrInfo = getAttributeInfo(qName); 167 168 String typeName = null; 169 170 boolean isFragment = false; 171 Method method = getAttributeMethod(qName); 172 173 Class type = null; 174 175 if (method != null) 176 type = method.getParameterTypes()[0]; 177 178 if (attrInfo != null) { 179 typeName = attrInfo.getTypeName(); 180 isFragment = attrInfo.isFragment(); 181 182 if (isFragment && 183 type != null && type.isAssignableFrom(JspFragment.class)) 184 typeName = JspFragment.class.getName(); 185 } 186 else if (method != null) 187 typeName = type.getName(); 188 189 if (! isFragment && ! JspFragment.class.getName().equals(typeName)) { 190 } 191 else if (value instanceof JspAttribute) { 192 JspAttribute jspAttr = (JspAttribute) value; 193 194 jspAttr.setJspFragment(true); 195 } 196 } 197 198 TagData tagData = new TagData(tags); 199 200 _varInfo = _tagInfo.getVariableInfo(tagData); 201 202 if (_varInfo == null) 203 _varInfo = fillVariableInfo(_tagInfo.getTagVariableInfos(), tagData); 204 205 TagExtraInfo tei = _tagInfo.getTagExtraInfo(); 206 ValidationMessage []messages; 207 if (tei != null) { 208 messages = tei.validate(tagData); 209 210 _gen.addDepend(tei.getClass()); 211 212 if (messages != null && messages.length != 0) { 213 throw error(messages[0].getMessage()); 214 } 215 } 216 } 217 218 221 public boolean hasScripting() 222 { 223 if (super.hasScripting()) 224 return true; 225 226 for (int i = 0; i < _attributeValues.size(); i++) { 228 QName name = _attributeNames.get(i); 229 Object value = _attributeValues.get(i); 230 231 try { 232 if (value instanceof String && hasRuntimeAttribute((String ) value)) 233 return true; 234 } catch (Throwable e) { 235 log.log(Level.WARNING, e.toString(), e); 236 return true; 237 } 238 } 239 240 return false; 241 } 242 243 246 public void generatePrologue(JspJavaWriter out) 247 throws Exception 248 { 249 for (int i = 0; i < _attributeNames.size(); i++) { 250 QName name = _attributeNames.get(i); 251 Object value = _attributeValues.get(i); 252 253 if (! (value instanceof JspFragmentNode)) 254 continue; 255 256 JspFragmentNode frag = (JspFragmentNode) value; 257 258 TagAttributeInfo attribute = getAttributeInfo(name); 259 String typeName = null; 260 261 boolean isFragment = false; 262 263 if (attribute != null && attribute.isFragment()) 264 isFragment = true; 265 266 String fragmentClass = JspFragment.class.getName(); 267 268 if (attribute != null && fragmentClass.equals(attribute.getTypeName())) 269 isFragment = true; 270 271 Method method = getAttributeMethod(name); 272 273 if (method != null) { 274 typeName = method.getParameterTypes()[0].getName(); 275 if (fragmentClass.equals(typeName)) 276 isFragment = true; 277 } 278 279 if (isFragment) 280 frag.generateFragmentPrologue(out); 281 } 282 283 TagInstance parent = getParent().getTag(); 284 285 boolean isBodyTag = BodyTag.class.isAssignableFrom(_tagClass); 286 boolean isEmpty = isEmpty(); 287 boolean hasBodyContent = isBodyTag && ! isEmpty; 288 289 _tag = parent.findTag(getQName(), _attributeNames, 290 hasBodyContent); 291 292 if (_tag == null || ! _parseState.isRecycleTags()) { 293 _tag = parent.addTag(getQName(), _tagInfo, _tagClass, 294 _attributeNames, _attributeValues, 295 hasBodyContent); 296 297 if (! JspTagFileSupport.class.isAssignableFrom(_tagClass)) { 298 out.printClass(_tagClass); 299 out.println(" " + _tag.getId() + " = null;"); 300 } 301 302 306 } 307 else { 308 for (int i = 0; i < _attributeNames.size(); i++) { 310 QName name = _attributeNames.get(i); 311 Object value = _attributeValues.get(i); 312 313 _tag.addAttribute(name, value); 314 } 315 } 316 317 if (_tag == null) 318 throw new NullPointerException (); 319 320 324 325 generatePrologueDeclare(out); 326 generatePrologueChildren(out); 327 } 328 329 public void generatePrologueDeclare(JspJavaWriter out) 330 throws Exception 331 { 332 for (int i = 0; _varInfo != null && i < _varInfo.length; i++) { 334 VariableInfo var = _varInfo[i]; 335 336 if (var == null) { 337 } 338 else if (! _gen.hasScripting()) { 339 } 340 else if ((var.getScope() == VariableInfo.AT_END 341 || var.getScope() == VariableInfo.AT_BEGIN) 342 && var.getDeclare() 343 && ! _gen.isDeclared(var.getVarName())) { 344 String className = var.getClassName(); 345 346 if (className == null) 347 className = DEFAULT_VAR_TYPE; 348 349 validateClass(className, var.getVarName()); 350 351 out.print(className + " " + var.getVarName() + " = "); 352 353 _gen.addDeclared(var.getVarName()); 354 355 if ("byte".equals(var.getClassName()) || 356 "short".equals(var.getClassName()) || 357 "char".equals(var.getClassName()) || 358 "int".equals(var.getClassName()) || 359 "long".equals(var.getClassName()) || 360 "float".equals(var.getClassName()) || 361 "double".equals(var.getClassName())) 362 out.println("0;"); 363 else if ("boolean".equals(var.getClassName())) 364 out.println("false;"); 365 else 366 out.println("null;"); 367 } 368 } 369 } 370 371 376 public void printXml(WriteStream os) 377 throws IOException 378 { 379 TagInfo tag = getTagInfo(); 380 381 String name = tag.getTagLibrary().getPrefixString() + ':' + tag.getTagName(); 382 383 os.print("<" + name); 384 385 printJspId(os); 386 387 for (int i = 0; i < _attributeNames.size(); i++) { 388 QName attrName = _attributeNames.get(i); 389 Object value = _attributeValues.get(i); 390 391 if (value instanceof String ) { 392 String string = (String ) value; 393 394 os.print(" " + attrName.getName() + "=\""); 395 396 if (string.startsWith("<%=") && string.endsWith("%>")) { 397 os.print("%="); 398 os.print(xmlAttrText(string.substring(3, string.length() - 2))); 399 os.print("%"); 400 } 401 else 402 os.print(xmlAttrText(string)); 403 404 os.print("\""); 405 } 406 } 407 408 os.print(">"); 409 410 printXmlChildren(os); 411 412 os.print("</" + name + ">"); 413 } 414 415 420 abstract public void generate(JspJavaWriter out) 421 throws Exception ; 422 423 protected void fillAttributes(JspJavaWriter out, String name) 424 throws Exception 425 { 426 TagAttributeInfo attrs[] = _tagInfo.getAttributes(); 427 428 for (int i = 0; attrs != null && i < attrs.length; i++) { 430 int p = getAttributeIndex(attrs[i].getName()); 431 432 if (p < 0 && attrs[i].isRequired()) { 433 throw error(L.l("required attribute '{0}' missing from <{1}>", 434 attrs[i].getName(), 435 getTagName())); 436 } 437 } 438 439 boolean isDynamic = DynamicAttributes.class.isAssignableFrom(_tagClass); 440 441 for (int i = 0; i < _attributeNames.size(); i++) { 443 QName attrName = _attributeNames.get(i); 444 Object value = _attributeValues.get(i); 445 446 TagAttributeInfo attribute = getAttributeInfo(attrName); 447 448 if (attrs != null && attribute == null && ! isDynamic) 449 throw error(L.l("unexpected attribute '{0}' in <{1}>", 450 attrName.getName(), getTagName())); 451 452 if (_tag.getAttribute(attrName) != null) 453 continue; 454 455 boolean isFragment = false; 456 457 if (attribute != null) { 458 isFragment = (attribute.isFragment() || 459 attribute.getTypeName().equals(JspFragment.class.getName())); 460 } 461 462 if (value instanceof JspAttribute && 463 ((JspAttribute) value).isJspFragment()) 464 isFragment = true; 465 466 generateSetAttribute(out, name, attrName, value, 467 attribute == null || attribute.canBeRequestTime(), 468 isFragment, attribute); 469 } 470 } 471 472 private TagAttributeInfo getAttributeInfo(QName attrName) 473 { 474 TagAttributeInfo attrs[] = _tagInfo.getAttributes(); 475 476 int j = 0; 477 for (j = 0; attrs != null && j < attrs.length; j++) { 478 if (isNameMatch(attrs[j].getName(), attrName)) 479 return attrs[j]; 480 } 481 482 return null; 483 } 484 485 private int getAttributeIndex(String name) 486 { 487 for (int i = 0; i < _attributeNames.size(); i++) { 488 QName attrName = _attributeNames.get(i); 489 490 if (isNameMatch(name, attrName)) 491 return i; 492 } 493 494 return -1; 495 } 496 497 private boolean isNameMatch(String defName, QName attrName) 498 { 499 if (defName.equals(attrName.getName())) { 500 return true; 501 } 502 else if (defName.equals(attrName.getLocalName()) && 503 attrName.getPrefix().equals(getQName().getPrefix())) { 504 return true; 505 } 506 else 507 return false; 508 } 509 510 518 void generateSetAttribute(JspJavaWriter out, 519 String name, QName attrName, Object value, 520 boolean allowRtexpr, boolean isFragment, 521 TagAttributeInfo attrInfo) 522 throws Exception 523 { 524 Method method = getAttributeMethod(attrName); 525 526 boolean isDynamic = DynamicAttributes.class.isAssignableFrom(_tagClass); 527 528 if (method != null) { 529 if (Modifier.isStatic(method.getModifiers())) 531 throw error(L.l("attribute '{0}' may not be a static method.", 532 method.getName())); 533 534 generateSetParameter(out, name, value, method, 535 allowRtexpr, "pageContext", isFragment, attrInfo); 536 } 537 else if (! isDynamic) { 538 throw error(L.l("attribute '{0}' in tag '{1}' has no corresponding set method in tag class '{2}'", 539 attrName.getName(), getTagName(), _tagClass.getName())); 540 } 541 else if (isFragment) { 542 String uri = attrName.getNamespaceURI(); 543 String local = attrName.getLocalName(); 544 545 out.print(name + ".setDynamicAttribute("); 546 547 if (uri == null) 548 out.print("null, "); 549 else 550 out.print("\"" + escapeJavaString(uri) + "\", "); 551 552 JspFragmentNode frag = (JspFragmentNode) value; 553 out.print("\"" + escapeJavaString(local) + "\", "); 554 out.print(frag.generateValue()); 555 out.println(");"); 556 } 557 else { 558 String uri = attrName.getNamespaceURI(); 559 String local = attrName.getLocalName(); 560 561 out.print(name + ".setDynamicAttribute("); 562 563 if (uri == null) 564 out.print("null, "); 565 else 566 out.print("\"" + escapeJavaString(uri) + "\", "); 567 568 out.print("\"" + escapeJavaString(local) + "\", "); 569 out.print(generateRTValue(Object .class, value)); 570 out.println(");"); 571 } 572 } 573 574 private Method getAttributeMethod(QName attrName) 575 throws Exception 576 { 577 Method method = null; 578 579 try { 580 BeanInfo info = Introspector.getBeanInfo(_tagClass); 581 582 if (info != null) 583 method = BeanUtil.getSetMethod(info, attrName.getLocalName()); 584 585 if (method != null) 586 return method; 587 } catch (Throwable e) { 588 log.log(Level.FINER, e.toString(), e); 589 } 590 591 601 602 return method; 603 } 604 605 608 protected boolean hasVarDeclaration(int scope) 609 throws Exception 610 { 611 for (int i = 0; _varInfo != null && i < _varInfo.length; i++) { 612 VariableInfo var = _varInfo[i]; 613 614 if (var != null && var.getScope() == scope) 615 return true; 616 } 617 618 return false; 619 } 620 621 628 protected void printVarDeclaration(JspJavaWriter out, int scope) 629 throws Exception 630 { 631 for (int i = 0; _varInfo != null && i < _varInfo.length; i++) { 632 VariableInfo var = _varInfo[i]; 633 634 if (var != null) { 635 printVarDeclare(out, scope, var); 636 printVarAssign(out, scope, var); 637 } 638 } 639 } 640 641 648 protected void printVarDeclare(JspJavaWriter out, int scope) 649 throws Exception 650 { 651 for (int i = 0; _varInfo != null && i < _varInfo.length; i++) { 652 VariableInfo var = _varInfo[i]; 653 654 if (var != null) 655 printVarDeclare(out, scope, var); 656 } 657 } 658 659 666 protected void printVarAssign(JspJavaWriter out, int scope) 667 throws Exception 668 { 669 for (int i = 0; _varInfo != null && i < _varInfo.length; i++) { 670 VariableInfo var = _varInfo[i]; 671 672 if (var != null) 673 printVarAssign(out, scope, var); 674 } 675 } 676 677 687 protected VariableInfo []fillVariableInfo(TagVariableInfo []tagVars, 688 TagData tagData) 689 throws JspParseException 690 { 691 if (tagVars == null) 692 return null; 693 694 VariableInfo []vars = new VariableInfo[tagVars.length]; 695 696 for (int i = 0; i < tagVars.length; i++) { 697 TagVariableInfo tagVar = tagVars[i]; 698 699 String name = null; 700 if (tagVar.getNameGiven() != null) 701 name = tagVar.getNameGiven(); 702 else { 703 String attributeName = tagVar.getNameFromAttribute(); 704 705 name = tagData.getAttributeString(attributeName); 706 707 if (name == null) 708 continue; 709 } 710 711 vars[i] = new VariableInfo(name, tagVar.getClassName(), 712 tagVar.getDeclare(), tagVar.getScope()); 713 } 714 715 return vars; 716 } 717 718 725 protected void printVarDeclare(JspJavaWriter out, 726 int scope, 727 VariableInfo var) 728 throws Exception 729 { 730 if (! _gen.hasScripting() || var == null) 731 return; 732 733 if (var.getScope() == scope 734 || var.getScope() == VariableInfo.AT_BEGIN) { 735 if (var.getVarName() == null) 736 throw error(L.l("tag variable expects a name")); 737 738 String className = var.getClassName(); 739 740 if (className == null) 741 className = DEFAULT_VAR_TYPE; 742 743 748 749 validateVarName(var.getVarName()); 750 751 if (var.getDeclare() 753 && var.getScope() == scope 754 && (var.getScope() == VariableInfo.NESTED && hasScripting() 755 || var.getScope() == VariableInfo.AT_BEGIN) 756 && ! varAlreadyDeclared(var.getVarName())) { 757 validateClass(className, var.getVarName()); 758 759 out.println(className + " " + var.getVarName() + ";"); 760 } 761 } 762 } 763 764 771 protected void printVarAssign(JspJavaWriter out, int scope, VariableInfo var) 772 throws Exception 773 { 774 if (var.getScope() == scope || 775 var.getScope() == VariableInfo.AT_BEGIN) { 776 if (var.getVarName() == null) 777 throw error(L.l("tag variable expects a name")); 778 779 String className = var.getClassName(); 780 781 if (className == null || className.equals("null")) 782 className = DEFAULT_VAR_TYPE; 783 784 789 790 validateVarName(var.getVarName()); 791 792 if (! _gen.hasScripting()) { 793 } 794 else if (var.getScope() != VariableInfo.NESTED || hasScripting()) { 795 out.setLocation(_filename, _startLine); 796 out.print(var.getVarName() + " = "); 797 String v = "pageContext.findAttribute(\"" + var.getVarName() + "\")"; 798 convertParameterValue(out, className, v); 799 out.println(";"); 800 } 801 802 _gen.addBeanClass(var.getVarName(), className); 803 } 804 } 805 806 private void validateVarName(String name) 807 throws JspParseException 808 { 809 if (! Character.isJavaIdentifierStart(name.charAt(0))) 810 throw error(L.l("tag variable '{0}' is an illegal Java identifier.", name)); 811 812 for (int i = 0; i < name.length(); i++) { 813 if (! Character.isJavaIdentifierPart(name.charAt(i))) 814 throw error(L.l("tag variable '{0}' is an illegal Java identifier.", name)); 815 } 816 } 817 818 821 private boolean varAlreadyDeclared(String varName) 822 { 823 if (_gen.isDeclared(varName)) 824 return true; 825 826 for (JspNode node = getParent(); 827 node != null; 828 node = node.getParent()) { 829 if (! (node instanceof GenericTag)) 830 continue; 831 if (node instanceof JspFragmentNode) 832 break; 833 834 GenericTag tag = (GenericTag) node; 835 836 VariableInfo []varInfo = tag.getVarInfo(); 837 838 for (int i = 0; varInfo != null && i < varInfo.length; i++) { 839 if (varInfo[i] == null) 840 continue; 841 else if (varInfo[i].getVarName().equals(varName)) 842 return true; 843 } 844 } 845 846 return false; 847 } 848 849 852 protected boolean isDeclared() 853 { 854 if (! _gen.getRecycleTags()) 855 return false; 856 857 JspNode parent = getParent(); 858 859 if (! (parent instanceof JspRoot) && 860 ! (parent instanceof JspTop) && 861 ! (parent instanceof GenericTag) && 862 ! (parent instanceof JspAttribute)) 863 return false; 864 865 boolean isDeclared = false; 866 867 ArrayList <JspNode> siblings = getParent().getChildren(); 868 for (int i = 0; i < siblings.size(); i++) { 869 JspNode node = siblings.get(i); 870 871 if (node == this) { 872 return isDeclared; 873 } 874 875 if (hasScriptlet(node)) { 876 return false; 877 } 878 879 if (node instanceof GenericTag) { 880 GenericTag customTag = (GenericTag) node; 881 882 if (customTag.getTag() == getTag()) 883 isDeclared = true; 884 } 885 } 886 887 return isDeclared; 888 } 889 890 893 protected boolean hasScriptlet(JspNode node) 894 { 895 if (node instanceof JspScriptlet || node instanceof JspExpression) 896 return true; 897 898 ArrayList <JspNode> children = node.getChildren(); 899 900 if (children == null) 901 return false; 902 903 for (int i = 0; i < children.size(); i++) { 904 JspNode child = children.get(i); 905 906 if (hasScriptlet(child)) 907 return true; 908 } 909 910 return false; 911 } 912 913 916 protected void validateClass(String className, String varName) 917 throws JspParseException 918 { 919 try { 920 if (_primTypes.contains(className)) 921 return; 922 else if (className.endsWith("[]")) { 923 validateClass(className.substring(0, className.length() - 2), varName); 924 return; 925 } 926 927 Class cl = _gen.getBeanClass(className); 928 } catch (ClassNotFoundException e) { 929 throw error(L.l("'{0}' is an unknown class for tag variable '{1}'.", 930 className, varName)); 931 } 932 } 933 934 static { 935 _primTypes.add("boolean"); 936 _primTypes.add("byte"); 937 _primTypes.add("short"); 938 _primTypes.add("int"); 939 _primTypes.add("long"); 940 _primTypes.add("float"); 941 _primTypes.add("double"); 942 _primTypes.add("char"); 943 } 944 } 945 | Popular Tags |