001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.jsp.java;
031:
032: import com.caucho.jsp.JspParseException;
033: import com.caucho.jsp.TagInstance;
034: import com.caucho.util.BeanUtil;
035: import com.caucho.vfs.WriteStream;
036: import com.caucho.xml.QName;
037:
038: import javax.servlet.jsp.tagext.*;
039: import java.beans.BeanInfo;
040: import java.beans.Introspector;
041: import java.io.IOException;
042: import java.lang.reflect.Method;
043: import java.lang.reflect.Modifier;
044: import java.util.ArrayList;
045: import java.util.HashSet;
046: import java.util.Hashtable;
047: import java.util.logging.Level;
048:
049: /**
050: * Represents a custom tag.
051: */
052: abstract public class GenericTag extends JspContainerNode {
053: private static final String DEFAULT_VAR_TYPE = "java.lang.String";
054:
055: private static final HashSet<String> _primTypes = new HashSet<String>();
056:
057: protected TagInstance _tag;
058: protected TagInfo _tagInfo;
059: protected Class _tagClass;
060: protected VariableInfo[] _varInfo;
061:
062: public GenericTag() {
063: }
064:
065: public void setTagInfo(TagInfo tagInfo) {
066: _tagInfo = tagInfo;
067: }
068:
069: public TagInfo getTagInfo() {
070: return _tagInfo;
071: }
072:
073: @Override
074: public boolean isPre21Taglib() {
075: if (_tagInfo == null)
076: return false;
077:
078: TagLibraryInfo library = _tagInfo.getTagLibrary();
079:
080: if (library == null || library.getRequiredVersion() == null)
081: return false;
082:
083: return "2.1".compareTo(library.getRequiredVersion()) > 0;
084: }
085:
086: public TagInstance getTag() {
087: return _tag;
088: }
089:
090: /**
091: * Returns the tag name for the current tag.
092: */
093: public String getCustomTagName() {
094: return _tag.getId();
095: }
096:
097: /**
098: * Returns true if the tag is a simple tag.
099: */
100: public boolean isSimple() {
101: return _tag.isSimpleTag();
102: }
103:
104: /**
105: * True if this is a jstl node.
106: */
107: public boolean isJstl() {
108: String uri = _tag.getTagInfo().getTagLibrary().getURI();
109:
110: return (JavaJspBuilder.JSTL_CORE_URI.equals(uri)
111: || JavaJspBuilder.JSTL_EL_CORE_URI.equals(uri)
112: || JavaJspBuilder.JSTL_FMT_URI.equals(uri)
113: || JavaJspBuilder.JSTL_XML_URI.equals(uri) || JavaJspBuilder.JSTL_SQL_URI
114: .equals(uri));
115: }
116:
117: public void setTagClass(Class cl) {
118: _tagClass = cl;
119: }
120:
121: public VariableInfo[] getVarInfo() {
122: return _varInfo;
123: }
124:
125: /**
126: * Returns the body content.
127: */
128: public String getBodyContent() {
129: return _tagInfo.getBodyContent();
130: }
131:
132: /**
133: * Adds a child node.
134: */
135: public void addChild(JspNode node) throws JspParseException {
136: if (!"empty".equals(getBodyContent()))
137: super .addChild(node);
138: else if (node instanceof JspAttribute) {
139: super .addChild(node);
140: } else if (node instanceof StaticText
141: && ((StaticText) node).isWhitespace()) {
142: } else {
143: throw error(L
144: .l(
145: "<{0}> must be empty. Since <{0}> has a body-content of 'empty', it must not have any content.",
146: getTagName()));
147: }
148: }
149:
150: /**
151: * Completes the element
152: */
153: public void endElement() throws Exception {
154: if (_tagClass != null)
155: _gen.addDepend(_tagClass);
156:
157: Hashtable<String, Object> tags = new Hashtable<String, Object>();
158:
159: for (int i = 0; i < _attributeNames.size(); i++) {
160: QName qName = _attributeNames.get(i);
161: Object value = _attributeValues.get(i);
162: String name = qName.getName();
163:
164: if (value instanceof JspAttribute) {
165: JspAttribute attr = (JspAttribute) value;
166:
167: if (attr.isStatic())
168: tags.put(name, attr.getStaticText());
169: else
170: tags.put(name, TagData.REQUEST_TIME_VALUE);
171: } else if (value instanceof String
172: && hasRuntimeAttribute((String) value))
173: tags.put(name, TagData.REQUEST_TIME_VALUE);
174: else
175: tags.put(name, value);
176:
177: TagAttributeInfo attrInfo = getAttributeInfo(qName);
178:
179: String typeName = null;
180:
181: boolean isFragment = false;
182: Method method = getAttributeMethod(qName);
183:
184: Class type = null;
185:
186: if (method != null)
187: type = method.getParameterTypes()[0];
188:
189: if (attrInfo != null) {
190: typeName = attrInfo.getTypeName();
191: isFragment = attrInfo.isFragment();
192:
193: if (isFragment && type != null
194: && type.isAssignableFrom(JspFragment.class))
195: typeName = JspFragment.class.getName();
196: } else if (method != null)
197: typeName = type.getName();
198:
199: if (!isFragment
200: && !JspFragment.class.getName().equals(typeName)) {
201: } else if (value instanceof JspAttribute) {
202: JspAttribute jspAttr = (JspAttribute) value;
203:
204: jspAttr.setJspFragment(true);
205: }
206: }
207:
208: TagData tagData = new TagData(tags);
209:
210: _varInfo = _tagInfo.getVariableInfo(tagData);
211:
212: if (_varInfo == null)
213: _varInfo = fillVariableInfo(_tagInfo.getTagVariableInfos(),
214: tagData);
215:
216: TagExtraInfo tei = _tagInfo.getTagExtraInfo();
217: ValidationMessage[] messages;
218: if (tei != null) {
219: messages = tei.validate(tagData);
220:
221: _gen.addDepend(tei.getClass());
222:
223: if (messages != null && messages.length != 0) {
224: throw error(messages[0].getMessage());
225: }
226: }
227: }
228:
229: /**
230: * True if the node has scripting
231: */
232: public boolean hasScripting() {
233: if (super .hasScripting())
234: return true;
235:
236: // Any conflicting values must be set each time.
237: for (int i = 0; i < _attributeValues.size(); i++) {
238: QName name = _attributeNames.get(i);
239: Object value = _attributeValues.get(i);
240:
241: try {
242: if (value instanceof String
243: && hasRuntimeAttribute((String) value))
244: return true;
245: } catch (Throwable e) {
246: log.log(Level.WARNING, e.toString(), e);
247: return true;
248: }
249: }
250:
251: return false;
252: }
253:
254: /**
255: * True if the jsf-parent setting is required.
256: */
257: @Override
258: public boolean isJsfParentRequired() {
259: return true;
260: }
261:
262: /**
263: * Returns the variable containing the jsf component
264: */
265: public String getJsfVar() {
266: return null;
267: }
268:
269: /**
270: * Returns the variable containing the jsf body
271: */
272: public String getJsfBodyVar() {
273: return null;
274: }
275:
276: /**
277: * Generates code before the actual JSP.
278: */
279: public void generatePrologue(JspJavaWriter out) throws Exception {
280: for (int i = 0; i < _attributeNames.size(); i++) {
281: QName name = _attributeNames.get(i);
282: Object value = _attributeValues.get(i);
283:
284: if (!(value instanceof JspFragmentNode))
285: continue;
286:
287: JspFragmentNode frag = (JspFragmentNode) value;
288:
289: TagAttributeInfo attribute = getAttributeInfo(name);
290: String typeName = null;
291:
292: boolean isFragment = false;
293:
294: if (attribute != null && attribute.isFragment())
295: isFragment = true;
296:
297: String fragmentClass = JspFragment.class.getName();
298:
299: if (attribute != null
300: && fragmentClass.equals(attribute.getTypeName()))
301: isFragment = true;
302:
303: Method method = getAttributeMethod(name);
304:
305: if (method != null) {
306: typeName = method.getParameterTypes()[0].getName();
307: if (fragmentClass.equals(typeName))
308: isFragment = true;
309: }
310:
311: if (isFragment)
312: frag.generateFragmentPrologue(out);
313: }
314:
315: TagInstance parent = getParent().getTag();
316:
317: boolean isBodyTag = BodyTag.class.isAssignableFrom(_tagClass);
318: boolean isEmpty = isEmpty();
319: boolean hasBodyContent = isBodyTag && !isEmpty;
320:
321: _tag = parent.findTag(getQName(), _attributeNames,
322: hasBodyContent);
323:
324: if (_tag == null || !_parseState.isRecycleTags()) {
325: _tag = parent.addTag(getQName(), _tagInfo, _tagClass,
326: _attributeNames, _attributeValues, hasBodyContent);
327:
328: if (!JspTagFileSupport.class.isAssignableFrom(_tagClass)) {
329: out.printClass(_tagClass);
330: out.println(" " + _tag.getId() + " = null;");
331: }
332:
333: /*
334: if (SimpleTag.class.isAssignableFrom(_tagClass) && hasCustomTag())
335: out.println("javax.servlet.jsp.tagext.Tag " + _tag.getId() + "_adapter = null;");
336: */
337: } else {
338: // Any conflicting values must be set each time.
339: for (int i = 0; i < _attributeNames.size(); i++) {
340: QName name = _attributeNames.get(i);
341: Object value = _attributeValues.get(i);
342:
343: _tag.addAttribute(name, value);
344: }
345: }
346:
347: if (_tag == null)
348: throw new NullPointerException();
349:
350: /* already taken care of
351: if (! isEmpty())
352: _tag.setBodyContent(true);
353: */
354:
355: generatePrologueDeclare(out);
356: generatePrologueChildren(out);
357: }
358:
359: public void generatePrologueDeclare(JspJavaWriter out)
360: throws Exception {
361: // Any AT_END variables
362: for (int i = 0; _varInfo != null && i < _varInfo.length; i++) {
363: VariableInfo var = _varInfo[i];
364:
365: if (var == null) {
366: } else if (!_gen.hasScripting()) {
367: } else if ((var.getScope() == VariableInfo.AT_END || var
368: .getScope() == VariableInfo.AT_BEGIN)
369: && var.getDeclare()
370: && !_gen.isDeclared(var.getVarName())) {
371: String className = var.getClassName();
372:
373: if (className == null || "".equals(className)
374: || "null".equals(className))
375: className = DEFAULT_VAR_TYPE;
376:
377: validateClass(className, var.getVarName());
378:
379: out.print(className + " " + var.getVarName() + " = ");
380:
381: _gen.addDeclared(var.getVarName());
382:
383: if ("byte".equals(var.getClassName())
384: || "short".equals(var.getClassName())
385: || "char".equals(var.getClassName())
386: || "int".equals(var.getClassName())
387: || "long".equals(var.getClassName())
388: || "float".equals(var.getClassName())
389: || "double".equals(var.getClassName()))
390: out.println("0;");
391: else if ("boolean".equals(var.getClassName()))
392: out.println("false;");
393: else
394: out.println("null;");
395: }
396: }
397: }
398:
399: /**
400: * Generates the XML text representation for the tag validation.
401: *
402: * @param os write stream to the generated XML.
403: */
404: public void printXml(WriteStream os) throws IOException {
405: TagInfo tag = getTagInfo();
406:
407: String name = tag.getTagLibrary().getPrefixString() + ':'
408: + tag.getTagName();
409:
410: os.print("<" + name);
411:
412: printJspId(os);
413:
414: for (int i = 0; i < _attributeNames.size(); i++) {
415: QName attrName = _attributeNames.get(i);
416: Object value = _attributeValues.get(i);
417:
418: if (value instanceof String) {
419: String string = (String) value;
420:
421: printXmlAttribute(os, attrName.getName(), string);
422: }
423: }
424:
425: os.print(">");
426:
427: printXmlChildren(os);
428:
429: os.print("</" + name + ">");
430: }
431:
432: /**
433: * Generates the code for a custom tag.
434: *
435: * @param out the output writer for the generated java.
436: */
437: abstract public void generate(JspJavaWriter out) throws Exception;
438:
439: protected void fillAttributes(JspJavaWriter out, String name)
440: throws Exception {
441: TagAttributeInfo attrs[] = _tagInfo.getAttributes();
442:
443: // clear any attributes mentioned in the taglib that aren't set
444: for (int i = 0; attrs != null && i < attrs.length; i++) {
445: int p = getAttributeIndex(attrs[i].getName());
446:
447: if (p < 0 && attrs[i].isRequired()) {
448: throw error(L.l(
449: "required attribute '{0}' missing from <{1}>",
450: attrs[i].getName(), getTagName()));
451: }
452: }
453:
454: boolean isDynamic = DynamicAttributes.class
455: .isAssignableFrom(_tagClass);
456:
457: // fill all mentioned attributes
458: for (int i = 0; i < _attributeNames.size(); i++) {
459: QName attrName = _attributeNames.get(i);
460: Object value = _attributeValues.get(i);
461:
462: TagAttributeInfo attribute = getAttributeInfo(attrName);
463:
464: if (attrs != null && attribute == null && !isDynamic)
465: throw error(L.l("unexpected attribute '{0}' in <{1}>",
466: attrName.getName(), getTagName()));
467:
468: if (_tag.getAttribute(attrName) != null)
469: continue;
470:
471: boolean isFragment = false;
472:
473: if (attribute != null) {
474: isFragment = (attribute.isFragment() || attribute
475: .getTypeName().equals(
476: JspFragment.class.getName()));
477: }
478:
479: if (value instanceof JspAttribute
480: && ((JspAttribute) value).isJspFragment())
481: isFragment = true;
482:
483: generateSetAttribute(out, name, attrName, value,
484: attribute == null || attribute.canBeRequestTime(),
485: isFragment, attribute);
486: }
487: }
488:
489: private TagAttributeInfo getAttributeInfo(QName attrName) {
490: TagAttributeInfo attrs[] = _tagInfo.getAttributes();
491:
492: int j = 0;
493: for (j = 0; attrs != null && j < attrs.length; j++) {
494: if (isNameMatch(attrs[j].getName(), attrName))
495: return attrs[j];
496: }
497:
498: return null;
499: }
500:
501: private int getAttributeIndex(String name) {
502: for (int i = 0; i < _attributeNames.size(); i++) {
503: QName attrName = _attributeNames.get(i);
504:
505: if (isNameMatch(name, attrName))
506: return i;
507: }
508:
509: return -1;
510: }
511:
512: private boolean isNameMatch(String defName, QName attrName) {
513: if (defName.equals(attrName.getName())) {
514: return true;
515: } else if (defName.equals(attrName.getLocalName())
516: && attrName.getPrefix().equals(getQName().getPrefix())) {
517: return true;
518: } else
519: return false;
520: }
521:
522: /**
523: * Sets an attribute for a tag
524: *
525: * @param info the tag's introspected information
526: * @param name the tag's Java variable name
527: * @param attrName the attribute name to set
528: * @param value the new value of the tag.
529: */
530: void generateSetAttribute(JspJavaWriter out, String name,
531: QName attrName, Object value, boolean allowRtexpr,
532: boolean isFragment, TagAttributeInfo attrInfo)
533: throws Exception {
534: Method method = getAttributeMethod(attrName);
535:
536: boolean isDynamic = DynamicAttributes.class
537: .isAssignableFrom(_tagClass);
538:
539: if (method != null) {
540: // jsp/18cq
541: if (Modifier.isStatic(method.getModifiers()))
542: throw error(L.l(
543: "attribute '{0}' may not be a static method.",
544: method.getName()));
545:
546: generateSetParameter(out, name, value, method, allowRtexpr,
547: "pageContext", isFragment, attrInfo);
548: } else if (!isDynamic) {
549: throw error(L
550: .l(
551: "attribute '{0}' in tag '{1}' has no corresponding set method in tag class '{2}'",
552: attrName.getName(), getTagName(), _tagClass
553: .getName()));
554: } else if (isFragment) {
555: String uri = attrName.getNamespaceURI();
556: String local = attrName.getLocalName();
557:
558: out.print(name + ".setDynamicAttribute(");
559:
560: if (uri == null)
561: out.print("null, ");
562: else
563: out.print("\"" + escapeJavaString(uri) + "\", ");
564:
565: JspFragmentNode frag = (JspFragmentNode) value;
566: out.print("\"" + escapeJavaString(local) + "\", ");
567: out.print(frag.generateValue());
568: out.println(");");
569: } else {
570: String uri = attrName.getNamespaceURI();
571: String local = attrName.getLocalName();
572:
573: out.print(name + ".setDynamicAttribute(");
574:
575: if (uri == null)
576: out.print("null, ");
577: else
578: out.print("\"" + escapeJavaString(uri) + "\", ");
579:
580: out.print("\"" + escapeJavaString(local) + "\", ");
581: out.print(generateRTValue(Object.class, value));
582: out.println(");");
583: }
584: }
585:
586: private Method getAttributeMethod(QName attrName) throws Exception {
587: Method method = null;
588:
589: try {
590: BeanInfo info = Introspector.getBeanInfo(_tagClass);
591:
592: if (info != null)
593: method = BeanUtil.getSetMethod(info, attrName
594: .getLocalName());
595:
596: if (method != null)
597: return method;
598: } catch (Throwable e) {
599: log.log(Level.FINER, e.toString(), e);
600: }
601:
602: /*
603: try {
604: method = BeanUtil.getSetMethod(_tagClass, attrName.getLocalName());
605:
606: if (method != null)
607: return method;
608: } catch (Throwable e) {
609: log.log(Level.FINER, e.toString(), e);
610: }
611: */
612:
613: return method;
614: }
615:
616: /**
617: * Returns true if there is a tag variable declaration matching the scope.
618: */
619: protected boolean hasVarDeclaration(int scope) throws Exception {
620: for (int i = 0; _varInfo != null && i < _varInfo.length; i++) {
621: VariableInfo var = _varInfo[i];
622:
623: if (var != null && var.getScope() == scope)
624: return true;
625: }
626:
627: return false;
628: }
629:
630: /**
631: * Prints a tag variable declaration. Only the variables matching the
632: * scope will be printed.
633: *
634: * @param out the stream to the java code.
635: * @param scope the variable scope to print
636: */
637: protected void printVarDeclaration(JspJavaWriter out, int scope)
638: throws Exception {
639: for (int i = 0; _varInfo != null && i < _varInfo.length; i++) {
640: VariableInfo var = _varInfo[i];
641:
642: if (var != null) {
643: printVarDeclare(out, scope, var);
644: printVarAssign(out, scope, var);
645: }
646: }
647: }
648:
649: /**
650: * Prints a tag variable declaration. Only the variables matching the
651: * scope will be printed.
652: *
653: * @param out the stream to the java code.
654: * @param scope the variable scope to print
655: */
656: protected void printVarDeclare(JspJavaWriter out, int scope)
657: throws Exception {
658: for (int i = 0; _varInfo != null && i < _varInfo.length; i++) {
659: VariableInfo var = _varInfo[i];
660:
661: if (var != null)
662: printVarDeclare(out, scope, var);
663: }
664: }
665:
666: /**
667: * Prints a tag variable declaration. Only the variables matching the
668: * scope will be printed.
669: *
670: * @param out the stream to the java code.
671: * @param scope the variable scope to print
672: */
673: protected void printVarAssign(JspJavaWriter out, int scope)
674: throws Exception {
675: for (int i = 0; _varInfo != null && i < _varInfo.length; i++) {
676: VariableInfo var = _varInfo[i];
677:
678: if (var != null)
679: printVarAssign(out, scope, var);
680: }
681: }
682:
683: /**
684: * Returns the VariableInfo corresponding the to tag vars and the tag
685: * data. Mainly, this means looking up the variable names from the
686: * attributes for the name-from-attribute.
687: *
688: * @param tagVars the implicit tag variables for the tag
689: * @param tagData the parsed tag attributes
690: *
691: * @return an array of filled VariableInfo
692: */
693: protected VariableInfo[] fillVariableInfo(
694: TagVariableInfo[] tagVars, TagData tagData)
695: throws JspParseException {
696: if (tagVars == null)
697: return null;
698:
699: VariableInfo[] vars = new VariableInfo[tagVars.length];
700:
701: for (int i = 0; i < tagVars.length; i++) {
702: TagVariableInfo tagVar = tagVars[i];
703:
704: String name = null;
705: if (tagVar.getNameGiven() != null)
706: name = tagVar.getNameGiven();
707: else {
708: String attributeName = tagVar.getNameFromAttribute();
709:
710: name = tagData.getAttributeString(attributeName);
711:
712: if (name == null || "".equals(name)
713: || "null".equals(name))
714: continue;
715: }
716:
717: vars[i] = new VariableInfo(name, tagVar.getClassName(),
718: tagVar.getDeclare(), tagVar.getScope());
719: }
720:
721: return vars;
722: }
723:
724: /**
725: * Prints a tag variable declaration. Only the variables matching the
726: * scope will be printed.
727: *
728: * @param out the stream to the java code.
729: * @param scope the variable scope to print
730: */
731: protected void printVarDeclare(JspJavaWriter out, int scope,
732: VariableInfo var) throws Exception {
733: if (!_gen.hasScripting() || var == null
734: || var.getVarName() == null
735: || "".equals(var.getVarName())
736: || "null".equals(var.getVarName()))
737: return;
738:
739: if (var.getScope() == scope
740: || var.getScope() == VariableInfo.AT_BEGIN) {
741: if (var.getVarName() == null)
742: throw error(L.l("tag variable expects a name"));
743:
744: String className = var.getClassName();
745:
746: if (className == null || "".equals(className)
747: || "null".equals(className))
748: className = DEFAULT_VAR_TYPE;
749:
750: /*
751: if (var.getClassName() == null)
752: throw error(L.l("tag variable '{0}' expects a classname",
753: var.getVarName()));
754: */
755:
756: validateVarName(var.getVarName());
757:
758: // jsp/107r
759: if (var.getDeclare()
760: && var.getScope() == scope
761: && (var.getScope() == VariableInfo.NESTED
762: && hasScripting() || var.getScope() == VariableInfo.AT_BEGIN)
763: && !varAlreadyDeclared(var.getVarName())) {
764: validateClass(className, var.getVarName());
765:
766: out.println(className + " " + var.getVarName() + ";");
767: }
768: }
769: }
770:
771: /**
772: * Prints a tag variable declaration. Only the variables matching the
773: * scope will be printed.
774: *
775: * @param out the stream to the java code.
776: * @param scope the variable scope to print
777: */
778: protected void printVarAssign(JspJavaWriter out, int scope,
779: VariableInfo var) throws Exception {
780: if ("".equals(var.getVarName())
781: || "null".equals(var.getVarName()))
782: return;
783:
784: if (var.getScope() == scope
785: || var.getScope() == VariableInfo.AT_BEGIN) {
786: if (var.getVarName() == null)
787: throw error(L.l("tag variable expects a name"));
788:
789: String className = var.getClassName();
790:
791: if (className == null || className.equals("null"))
792: className = DEFAULT_VAR_TYPE;
793:
794: /*
795: if (var.getClassName() == null)
796: throw error(L.l("tag variable '{0}' expects a classname",
797: var.getVarName()));
798: */
799:
800: validateVarName(var.getVarName());
801:
802: if (!_gen.hasScripting()) {
803: } else if (var.getScope() != VariableInfo.NESTED
804: || hasScripting()) {
805: out.setLocation(_filename, _startLine);
806: out.print(var.getVarName() + " = ");
807: String v = "pageContext.findAttribute(\""
808: + var.getVarName() + "\")";
809: convertParameterValue(out, className, v);
810: out.println(";");
811: }
812:
813: try {
814: _gen.addBeanClass(var.getVarName(), className);
815: } catch (Exception e) {
816: Throwable cause = e.getCause();
817:
818: if (cause == null)
819: cause = e;
820:
821: throw error(
822: L
823: .l(
824: "'{0}' is an unknown class for tag variable '{1}' in <{2}>",
825: className, var.getVarName(),
826: getTagInfo().getTagName()),
827: cause);
828: }
829: }
830: }
831:
832: private void validateVarName(String name) throws JspParseException {
833: if (!Character.isJavaIdentifierStart(name.charAt(0)))
834: throw error(L
835: .l(
836: "tag variable '{0}' is an illegal Java identifier.",
837: name));
838:
839: for (int i = 0; i < name.length(); i++) {
840: if (!Character.isJavaIdentifierPart(name.charAt(i)))
841: throw error(L
842: .l(
843: "tag variable '{0}' is an illegal Java identifier.",
844: name));
845: }
846: }
847:
848: /**
849: * Returns true if the variable has been declared.
850: */
851: private boolean varAlreadyDeclared(String varName) {
852: if (_gen.isDeclared(varName))
853: return true;
854:
855: for (JspNode node = getParent(); node != null; node = node
856: .getParent()) {
857: if (!(node instanceof GenericTag))
858: continue;
859: if (node instanceof JspFragmentNode)
860: break;
861:
862: GenericTag tag = (GenericTag) node;
863:
864: VariableInfo[] varInfo = tag.getVarInfo();
865:
866: for (int i = 0; varInfo != null && i < varInfo.length; i++) {
867: if (varInfo[i] == null)
868: continue;
869: else if (varInfo[i].getVarName().equals(varName))
870: return true;
871: }
872: }
873:
874: return false;
875: }
876:
877: /**
878: * Returns true if the tag instance has been declared
879: */
880: protected boolean isDeclared() {
881: if (!_gen.getRecycleTags())
882: return false;
883:
884: JspNode parent = getParent();
885:
886: if (!(parent instanceof JspRoot) && !(parent instanceof JspTop)
887: && !(parent instanceof GenericTag)
888: && !(parent instanceof JspAttribute))
889: return false;
890:
891: boolean isDeclared = false;
892:
893: ArrayList<JspNode> siblings = getParent().getChildren();
894: for (int i = 0; i < siblings.size(); i++) {
895: JspNode node = siblings.get(i);
896:
897: if (node == this ) {
898: return isDeclared;
899: }
900:
901: if (hasScriptlet(node)) {
902: return false;
903: }
904:
905: if (node instanceof GenericTag) {
906: GenericTag customTag = (GenericTag) node;
907:
908: if (customTag.getTag() == getTag())
909: isDeclared = true;
910: }
911: }
912:
913: return isDeclared;
914: }
915:
916: /**
917: * Returns true if the node or one of its children is a scriptlet
918: */
919: protected boolean hasScriptlet(JspNode node) {
920: if (node instanceof JspScriptlet
921: || node instanceof JspExpression)
922: return true;
923:
924: ArrayList<JspNode> children = node.getChildren();
925:
926: if (children == null)
927: return false;
928:
929: for (int i = 0; i < children.size(); i++) {
930: JspNode child = children.get(i);
931:
932: if (hasScriptlet(child))
933: return true;
934: }
935:
936: return false;
937: }
938:
939: /**
940: * Checks that the given class is a valid variable class.
941: */
942: protected void validateClass(String className, String varName)
943: throws JspParseException {
944: try {
945: if (_primTypes.contains(className))
946: return;
947: else if (className.endsWith("[]")) {
948: validateClass(className.substring(0,
949: className.length() - 2), varName);
950: return;
951: }
952:
953: Class cl = _gen.getBeanClass(className);
954: } catch (ClassNotFoundException e) {
955: throw error(L
956: .l(
957: "'{0}' is an unknown class for tag variable '{1}'.",
958: className, varName));
959: }
960: }
961:
962: static {
963: _primTypes.add("boolean");
964: _primTypes.add("byte");
965: _primTypes.add("short");
966: _primTypes.add("int");
967: _primTypes.add("long");
968: _primTypes.add("float");
969: _primTypes.add("double");
970: _primTypes.add("char");
971: }
972: }
|