As discussed with Kin-Man, the following patch (for Jasper2) addresses two issues related to scripting variables exposed by custom tags (via TagExtraInfo class or TLD):
ISSUE 1: +++++++ According to the JSP spec, scripting variables with scope AT_BEGIN or AT_END are supposed to be visible from the begin element or end element, respectively, of the custom tag that is exposing them, all the way to the *end* of the page. This currently is not the case. The attached patch addresses this problem by determining the AT_BEGIN and AT_END scripting variables of any custom tag and declaring them as local variables of the _jspService() method. ISSUE 2: +++++++ If a custom tag exposing scripting variables is nested inside itself, its scripting variables get declared multiple times within the same scope of the generated code, resulting in compilation errors. This problem has been filed as bug #8926 (Synopsis: "Duplicate variable definition in generated Java source, related to custom tag scripting variable"). The attached patch addresses this problem by declaring AT_BEGIN and AT_END scripting variables once (as local variables of the _jspService() method, see above), and declaring NESTED scripting variables only at the outermost nesting level of their custom tag, where "nesting level" corresponds the number of times the custom tag is nested inside itself. Example: <g:h> <a:b> -- nesting level 0, declares NESTED scripting variables <c:d> <e:f> <a:b> -- nesting level 1, saves scripting variables <a:b> -- nesting level 2, saves scripting variables </a:b> -- restores scripting variables </a:b> -- restores scripting variables <a:b> -- nesting level 1, saves scripting variables </a:b> -- restores scripting variables </e:f> </c:d> </a:b> <a:b> -- nesting level 0, does not declare any NESTED scripting variables </a:b> </g:h> If <a:b> exposes any NESTED scripting variables, those variables are going to be declared only once in the generated code, namely by the *first* <a:b> at nesting level 0. Any <a:b> with a nesting level > 0 saves (in its begin element) the current values of all its scripting variables to locale variables (named for the scripting variable and the custom tag's nesting level) before synchronizing the scripting variables as defined by the JSP spec. In its end element, the custom tag restores the original values of the scripting variables (that is, the values the scripting variables had when the tag's begin element was encountered). In addition, this patch stores a custom tag's scripting variables with the custom tag itself, so the scripting variables don't need to be determined over and over again. This has resulted in two new accessor methods for Node.CustomTag: public TagVariableInfo[] getTagVariableInfos() public VariableInfo[] getVariableInfos() Let me know if there are any problems with this patch. Thanks, Jan
Executing ssh-askpass to query the password... Warning: Remote host denied X11 forwarding, perhaps xauth program could not be run on the server side. ? build.properties ? build ? src/share/org/apache/jasper/compiler/Generator.java.SAVE cvs server: Diffing . cvs server: Diffing doc cvs server: Diffing src cvs server: Diffing src/bin cvs server: Diffing src/share cvs server: Diffing src/share/org cvs server: Diffing src/share/org/apache cvs server: Diffing src/share/org/apache/jasper cvs server: Diffing src/share/org/apache/jasper/compiler Index: src/share/org/apache/jasper/compiler/Generator.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Generator.java,v retrieving revision 1.23 diff -u -r1.23 Generator.java --- src/share/org/apache/jasper/compiler/Generator.java 10 Jun 2002 21:08:30 -0000 1.23 +++ src/share/org/apache/jasper/compiler/Generator.java 12 Jun 2002 21:49:23 -0000 @@ -184,13 +184,15 @@ */ public void visit(Node.CustomTag n) throws JasperException { + // Create tag handler pool name and assign it to node String name = createTagHandlerPoolName(n.getPrefix(), - n.getShortName(), - n.getAttributes()); + n.getShortName(), + n.getAttributes()); n.setTagHandlerPoolName(name); if (!names.contains(name)) { names.add(name); } + visitBody(n); } @@ -235,6 +237,80 @@ page.visit(new TagHandlerPoolVisitor(tagHandlerPoolNames)); } + /* + * For every custom tag, declares its scripting variables with AT_BEGIN + * and AT_END scopes. + */ + private void declareAtBeginAtEndScriptingVariables(Node.Nodes page) + throws JasperException { + + class ScriptingVariableDeclarationVisitor extends Node.Visitor { + + /* + * Vector keeping track of which scripting variables have already + * been declared + */ + private Vector scriptVars; + + /* + * Constructor. + */ + public ScriptingVariableDeclarationVisitor() { + scriptVars = new Vector(); + } + + public void visit(Node.CustomTag n) throws JasperException { + + TagVariableInfo[] tagVarInfos = n.getTagVariableInfos(); + VariableInfo[] varInfos = n.getVariableInfos(); + + if ((varInfos == null) && (tagVarInfos == null)) { + visitBody(n); + } + + if (varInfos != null) { + for (int i=0; i<varInfos.length; i++) { + int scope = varInfos[i].getScope(); + String varName = varInfos[i].getVarName(); + if (((scope == VariableInfo.AT_BEGIN) + || (scope == VariableInfo.AT_END)) + && varInfos[i].getDeclare() + && !scriptVars.contains(varName)) { + out.printin(varInfos[i].getClassName()); + out.print(" "); + out.print(varName); + out.println(" = null;"); + scriptVars.add(varName); + } + } + } else { + for (int i=0; i<tagVarInfos.length; i++) { + int scope = tagVarInfos[i].getScope(); + String varName = tagVarInfos[i].getNameGiven(); + if (varName == null) { + varName = n.getTagData().getAttributeString( + tagVarInfos[i].getNameFromAttribute()); + } + if (((scope == VariableInfo.AT_BEGIN) + || (scope == VariableInfo.AT_END)) + && tagVarInfos[i].getDeclare() + && !scriptVars.contains(varName)) { + out.printin(tagVarInfos[i].getClassName()); + out.print(" "); + out.print(varName); + out.println(" = null;"); + scriptVars.add(varName); + } + } + } + + visitBody(n); + } + } + + page.visit(new ScriptingVariableDeclarationVisitor()); + } + /** * Generates the destroy() method which is responsible for calling the * release() method on every tag handler in any of the tag handler pools. @@ -376,6 +452,10 @@ if (maxTagNesting > 0) { out.printil("JspxState _jspxState = new JspxState();"); } + out.println(); + + declareAtBeginAtEndScriptingVariables(page); + out.println(); out.printil("try {"); out.pushIndent(); @@ -470,14 +550,26 @@ private ServletWriter out; private MethodsBuffer methodsBuffer; + /* + * Maps temporary scripting variable to parent of custom tag that + * declared it + */ + private Hashtable tmpVars; + + // Maps NESTED scripting var to parent of custom tag that declared it + private Hashtable nestedVars; + /** * Constructor. */ - public GenerateVisitor(ServletWriter out, MethodsBuffer methodsBuffer) { + public GenerateVisitor(ServletWriter out, + MethodsBuffer methodsBuffer) { this.out = out; this.methodsBuffer = methodsBuffer; handlerInfos = new Hashtable(); tagVarNumbers = new Hashtable(); + tmpVars = new Hashtable(); + nestedVars = new Hashtable(); } /** @@ -976,16 +1068,8 @@ public void visit(Node.CustomTag n) throws JasperException { - TagLibraryInfo tagLibInfo = (TagLibraryInfo) - pageInfo.getTagLibraries().get(n.getPrefix()); - TagInfo tagInfo = tagLibInfo.getTag(n.getShortName()); - - // Get info on scripting variables created/manipulated by tag - VariableInfo[] varInfos = tagInfo.getVariableInfo(n.getTagData()); - TagVariableInfo[] tagVarInfos = tagInfo.getTagVariableInfos(); - - Hashtable handlerInfosByShortName - = (Hashtable) handlerInfos.get(n.getPrefix()); + Hashtable handlerInfosByShortName = (Hashtable) + handlerInfos.get(n.getPrefix()); if (handlerInfosByShortName == null) { handlerInfosByShortName = new Hashtable(); handlerInfos.put(n.getPrefix(), handlerInfosByShortName); @@ -993,8 +1077,11 @@ TagHandlerInfo handlerInfo = (TagHandlerInfo) handlerInfosByShortName.get(n.getShortName()); if (handlerInfo == null) { - handlerInfo = new TagHandlerInfo(n, tagInfo.getTagClassName(), - ctxt.getClassLoader(), err); + handlerInfo = new TagHandlerInfo( + n, + n.getTagInfo().getTagClassName(), + ctxt.getClassLoader(), + err); handlerInfosByShortName.put(n.getShortName(), handlerInfo); } @@ -1008,8 +1095,9 @@ // to a method. ServletWriter outSave = null; MethodsBuffer methodsBufferSave = null; - if (n.isScriptless() && varInfos == null && - (tagVarInfos == null || tagVarInfos.length == 0)) { + if (n.isScriptless() && n.getVariableInfos() == null && + (n.getTagVariableInfos() == null + || n.getTagVariableInfos().length == 0)) { // The tag handler and its body code can reside in a separate // method if it is scriptless and does not have any scripting // variable defined. @@ -1073,20 +1161,19 @@ } // Generate code for start tag, body, and end tag - generateCustomStart(n, varInfos, tagVarInfos, handlerInfo, - tagHandlerVar, tagEvalVar); + generateCustomStart(n, handlerInfo, tagHandlerVar, tagEvalVar); String tmpParent = parent; parent = tagHandlerVar; visitBody(n); parent = tmpParent; - generateCustomEnd(n, varInfos, tagVarInfos, - handlerInfo.getTagHandlerClass(), tagHandlerVar, - tagEvalVar); + generateCustomEnd(n, handlerInfo.getTagHandlerClass(), + tagHandlerVar, tagEvalVar); - if (n.isScriptless() && varInfos == null && - (tagVarInfos == null || tagVarInfos.length == 0)) { + if (n.isScriptless() && n.getVariableInfos() == null && + (n.getTagVariableInfos() == null + || n.getTagVariableInfos().length == 0)) { // Generate end of method out.popIndent(); out.printil("}"); @@ -1202,23 +1289,33 @@ } private void generateCustomStart(Node.CustomTag n, - VariableInfo[] varInfos, - TagVariableInfo[] tagVarInfos, TagHandlerInfo handlerInfo, String tagHandlerVar, String tagEvalVar) throws JasperException { + Class tagHandlerClass = handlerInfo.getTagHandlerClass(); + n.setBeginJavaLine(out.getJavaLine()); out.printin("/* ---- "); out.print(n.getName()); out.println(" ---- */"); - Class tagHandlerClass = handlerInfo.getTagHandlerClass(); - boolean implementsTryCatchFinally = TryCatchFinally.class.isAssignableFrom(tagHandlerClass); + /* + * Declare variables where current contents of scripting variables + * will be temporarily saved + */ + declareTemporaryScriptingVariables(n); + + // Declare scripting variables with NESTED scope + declareNestedScriptingVariables(n); + + // Save current value of scripting variables if required + saveScriptingVariables(n); + out.printin(tagHandlerClass.getName()); out.print(" "); out.print(tagHandlerVar); @@ -1245,9 +1342,8 @@ boolean isBodyTag = BodyTag.class.isAssignableFrom(tagHandlerClass); - // Declare and synchronize AT_BEGIN scripting variables - syncScriptingVariables(varInfos, tagVarInfos, n.getTagData(), - VariableInfo.AT_BEGIN, true); + // Synchronize AT_BEGIN scripting variables + syncScriptingVariables(n, VariableInfo.AT_BEGIN); if (n.getBody() != null) { out.printin("if ("); @@ -1295,23 +1391,21 @@ } } - - // Declare and synchronize NESTED scripting variables - syncScriptingVariables(varInfos, tagVarInfos, n.getTagData(), - VariableInfo.NESTED, true); + // Synchronize NESTED scripting variables + syncScriptingVariables(n, VariableInfo.NESTED); // Synchronize AT_BEGIN scripting variables - syncScriptingVariables(varInfos, tagVarInfos, n.getTagData(), - VariableInfo.AT_BEGIN, false); + syncScriptingVariables(n, VariableInfo.AT_BEGIN); }; private void generateCustomEnd(Node.CustomTag n, - VariableInfo[] varInfos, - TagVariableInfo[] tagVarInfos, - Class tagHandlerClass, + Class tagHandlerClass, String tagHandlerVar, String tagEvalVar) { + VariableInfo[] varInfos = n.getVariableInfos(); + TagVariableInfo[] tagVarInfos = n.getTagVariableInfos(); + boolean implementsIterationTag = IterationTag.class.isAssignableFrom(tagHandlerClass); boolean implementsBodyTag = @@ -1327,8 +1421,7 @@ } // Synchronize AT_BEGIN scripting variables - syncScriptingVariables(varInfos, tagVarInfos, n.getTagData(), - VariableInfo.AT_BEGIN, false); + syncScriptingVariables(n, VariableInfo.AT_BEGIN); if (n.getBody() != null) { if (implementsBodyTag) { @@ -1373,35 +1466,234 @@ out.print(tagHandlerVar); out.println(");"); out.popIndent(); - out.printil("}"); + out.println("}"); } else { out.printin(n.getTagHandlerPoolName()); - out.println(".reuse("); - out.printin(tagHandlerVar); + out.print(".reuse("); + out.print(tagHandlerVar); out.println(");"); } - // Declare and synchronize AT_END variables - syncScriptingVariables(varInfos, tagVarInfos, n.getTagData(), - VariableInfo.AT_END, true); + // Synchronize AT_END variables + syncScriptingVariables(n, VariableInfo.AT_END); + + restoreScriptingVariables(n); n.setEndJavaLine(out.getJavaLine()); } - private void syncScriptingVariables(VariableInfo[] varInfos, - TagVariableInfo[] tagVarInfos, - TagData tagData, - int scope, - boolean declare) { + /* + * Declares any NESTED scripting variables of the given custom tag, + * if the given custom tag is not nested inside itself (i.e, has a + * nesting level of zero). In addition, a NESTED scripting variable is + * declared only if it has not already been declared in the same scope + * in the generated code, that is, if this custom tag's parent is + * different from the parent of the custom tag that may already have + * declared this variable. + */ + private void declareNestedScriptingVariables(Node.CustomTag n) { + if (n.getCustomNestingLevel() > 0) { + return; + } + + TagVariableInfo[] tagVarInfos = n.getTagVariableInfos(); + VariableInfo[] varInfos = n.getVariableInfos(); if ((varInfos == null) && (tagVarInfos == null)) { return; } + if (varInfos != null) { for (int i=0; i<varInfos.length; i++) { - if (varInfos[i].getScope() == scope) { - if (declare && varInfos[i].getDeclare()) { - out.printin(varInfos[i].getClassName() + " "); + if ((varInfos[i].getScope() == VariableInfo.NESTED) + && varInfos[i].getDeclare()) { + String name = varInfos[i].getVarName(); + Node parent = (Node) nestedVars.get(name); + if ((parent == null) || (parent != n.getParent())) { + out.printin(varInfos[i].getClassName()); + out.print(" "); + out.print(name); + out.println(";"); + nestedVars.put(name, n.getParent()); + } + } + } + } else { + for (int i=0; i<tagVarInfos.length; i++) { + if ((tagVarInfos[i].getScope() == VariableInfo.NESTED) + && tagVarInfos[i].getDeclare()) { + String name = tagVarInfos[i].getNameGiven(); + if (name == null) { + name = n.getTagData().getAttributeString( + tagVarInfos[i].getNameFromAttribute()); } + Node parent = (Node) nestedVars.get(name); + if ((parent == null) || (parent != n.getParent())) { + out.printin(tagVarInfos[i].getClassName()); + out.print(" "); + out.print(name); + out.println(";"); + nestedVars.put(name, n.getParent()); + } + } + } + } + } + + /* + * For every scripting variable exposed by this custom tag, declares + * a variable where the current value of the scripting variable may + * be saved, so it can later be restored in this custom tag's end + * element. + */ + private void declareTemporaryScriptingVariables(Node.CustomTag n) { + if (n.getCustomNestingLevel() == 0) { + return; + } + + TagVariableInfo[] tagVarInfos = n.getTagVariableInfos(); + VariableInfo[] varInfos = n.getVariableInfos(); + if ((varInfos == null) && (tagVarInfos == null)) { + return; + } + + if (varInfos != null) { + for (int i=0; i<varInfos.length; i++) { + String tmpVarName = "_jspx_" + varInfos[i].getVarName() + + "_" + n.getCustomNestingLevel(); + Node parent = (Node) tmpVars.get(tmpVarName); + if ((parent == null) || (parent != n.getParent())) { + out.printin(varInfos[i].getClassName()); + out.print(" "); + out.print(tmpVarName); + out.println(";"); + tmpVars.put(tmpVarName, n.getParent()); + } + } + } else { + for (int i=0; i<tagVarInfos.length; i++) { + String varName = tagVarInfos[i].getNameGiven(); + if (varName == null) { + varName = n.getTagData().getAttributeString( + tagVarInfos[i].getNameFromAttribute()); + } + String tmpVarName = "_jspx_" + varName + "_" + + n.getCustomNestingLevel(); + Node parent = (Node) tmpVars.get(tmpVarName); + if ((parent == null) || (parent != n.getParent())) { + out.printin(tagVarInfos[i].getClassName()); + out.print(" "); + out.print(tmpVarName); + out.println(";"); + tmpVars.put(tmpVarName, n.getParent()); + } + } + } + } + + /* + * For each scripting variable of a custom tag with a nesting level + * greater than 0, save its value to a temporary variable so that the + * scripting variable can be synchronized inside the nested custom tag + * without affecting the value it had at the start element of the + * custom tag, which will be restored when the end element of the + * custom tag is reached. + */ + private void saveScriptingVariables(Node.CustomTag n) { + if (n.getCustomNestingLevel() == 0) { + return; + } + + TagVariableInfo[] tagVarInfos = n.getTagVariableInfos(); + VariableInfo[] varInfos = n.getVariableInfos(); + if ((varInfos == null) && (tagVarInfos == null)) { + return; + } + + if (varInfos != null) { + for (int i=0; i<varInfos.length; i++) { + String varName = varInfos[i].getVarName(); + String tmpVarName = "_jspx_" + varName + "_" + + n.getCustomNestingLevel(); + out.printin(tmpVarName); + out.print(" = "); + out.print(varName); + out.println(";"); + } + } else { + for (int i=0; i<tagVarInfos.length; i++) { + String varName = tagVarInfos[i].getNameGiven(); + if (varName == null) { + varName = n.getTagData().getAttributeString( + tagVarInfos[i].getNameFromAttribute()); + } + String tmpVarName = "_jspx_" + varName + "_" + + n.getCustomNestingLevel(); + out.printin(tmpVarName); + out.print(" = "); + out.print(varName); + out.println(";"); + } + } + } + + /* + * For each scripting variable of a custom tag with a nesting level + * greater than 0, restore its original value that was saved in the + * start element of the custom tag. + */ + private void restoreScriptingVariables(Node.CustomTag n) { + if (n.getCustomNestingLevel() == 0) { + return; + } + + TagVariableInfo[] tagVarInfos = n.getTagVariableInfos(); + VariableInfo[] varInfos = n.getVariableInfos(); + if ((varInfos == null) && (tagVarInfos == null)) { + return; + } + + if (varInfos != null) { + for (int i=0; i<varInfos.length; i++) { + String varName = varInfos[i].getVarName(); + String tmpVarName = "_jspx_" + varName + "_" + + n.getCustomNestingLevel(); + out.printin(varName); + out.print(" = "); + out.print(tmpVarName); + out.println(";"); + } + } else { + for (int i=0; i<tagVarInfos.length; i++) { + String varName = tagVarInfos[i].getNameGiven(); + if (varName == null) { + varName = n.getTagData().getAttributeString( + tagVarInfos[i].getNameFromAttribute()); + } + String tmpVarName = "_jspx_" + varName + "_" + + n.getCustomNestingLevel(); + out.printin(varName); + out.print(" = "); + out.print(tmpVarName); + out.println(";"); + } + } + } + + /* + * Synchronizes the scripting variables of the given custom tag for + * the given scope. + */ + private void syncScriptingVariables(Node.CustomTag n, int scope) { + TagVariableInfo[] tagVarInfos = n.getTagVariableInfos(); + VariableInfo[] varInfos = n.getVariableInfos(); + + if ((varInfos == null) && (tagVarInfos == null)) { + return; + } + + if (varInfos != null) { + for (int i=0; i<varInfos.length; i++) { + if (varInfos[i].getScope() == scope) { out.printin(varInfos[i].getVarName()); out.print(" = ("); out.print(varInfos[i].getClassName()); @@ -1412,14 +1704,11 @@ } } else { for (int i=0; i<tagVarInfos.length; i++) { - String name = tagVarInfos[i].getNameGiven(); - if (name == null) { - name = tagData.getAttributeString( - tagVarInfos[i].getNameFromAttribute()); - } if (tagVarInfos[i].getScope() == scope) { - if (declare && tagVarInfos[i].getDeclare()) { - out.printin(tagVarInfos[i].getClassName() + " "); + String name = tagVarInfos[i].getNameGiven(); + if (name == null) { + name = n.getTagData().getAttributeString( + tagVarInfos[i].getNameFromAttribute()); } out.printin(name); out.print(" = ("); Index: src/share/org/apache/jasper/compiler/JspDocumentParser.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/JspDocumentParser.java,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 JspDocumentParser.java --- src/share/org/apache/jasper/compiler/JspDocumentParser.java 28 Mar 2002 18:46:15 -0000 1.1.1.1 +++ src/share/org/apache/jasper/compiler/JspDocumentParser.java 12 Jun 2002 21:49:23 +-0000 @@ -62,7 +62,7 @@ import java.io.*; import java.util.Hashtable; -import javax.servlet.jsp.tagext.TagLibraryInfo; +import javax.servlet.jsp.tagext.*; import javax.xml.parsers.SAXParserFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; @@ -401,13 +401,14 @@ if (tagLibInfo == null) { return null; } - if (tagLibInfo.getTag(shortName) == null) { + TagInfo tagInfo = tagLibInfo.getTag(shortName); + if (tagInfo == null) { throw new SAXException(err.getString("jsp.error.bad_tag", shortName, prefix)); } return new Node.CustomTag(attrs, start, qName, prefix, shortName, - parent); + tagInfo, parent); } /* Index: src/share/org/apache/jasper/compiler/Node.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Node.java,v retrieving revision 1.12 diff -u -r1.12 Node.java --- src/share/org/apache/jasper/compiler/Node.java 8 Jun 2002 00:14:35 -0000 1.12 +++ src/share/org/apache/jasper/compiler/Node.java 12 Jun 2002 21:49:23 -0000 @@ -62,7 +62,7 @@ import java.util.*; import java.io.CharArrayWriter; -import javax.servlet.jsp.tagext.TagData; +import javax.servlet.jsp.tagext.*; import org.xml.sax.Attributes; import org.apache.jasper.JasperException; @@ -670,13 +670,19 @@ private boolean hasIncludeAction; private boolean hasSetProperty; private String tagHandlerPoolName; + private TagInfo tagInfo; + private VariableInfo[] varInfos; + private int nestingLevel; public CustomTag(Attributes attrs, Mark start, String name, - String prefix, String shortName, Node parent) { + String prefix, String shortName, + TagInfo tagInfo, Node parent) { super(attrs, start, parent); this.name = name; this.prefix = prefix; this.shortName = shortName; + this.tagInfo = tagInfo; + this.nestingLevel = computeCustomNestingLevel(); } public void accept(Visitor v) throws JasperException { @@ -714,6 +720,7 @@ public void setTagData(TagData tagData) { this.tagData = tagData; + this.varInfos = tagInfo.getVariableInfo(tagData); } public TagData getTagData() { @@ -752,14 +759,68 @@ return hasSetProperty; } + public void setTagHandlerPoolName(String s) { + tagHandlerPoolName = s; + } + public String getTagHandlerPoolName() { return tagHandlerPoolName; } - public void setTagHandlerPoolName(String s) { - tagHandlerPoolName = s; + public TagInfo getTagInfo() { + return tagInfo; + } + + public TagVariableInfo[] getTagVariableInfos() { + return tagInfo.getTagVariableInfos(); } + public VariableInfo[] getVariableInfos() { + return varInfos; + } + + /* + * Gets this custom tag's nesting level. + */ + public int getCustomNestingLevel() { + return nestingLevel; + } + + /* + * Computes this custom tag's nesting level, which corresponds to the + * number of times this custom tag is nested inside itself. + * + * Example: + * + * <g:h> + * <a:b> -- nesting level 0 + * <c:d> + * <e:f> + * <a:b> -- nesting level 1 + * <a:b> -- nesting level 2 + * </a:b> + * </a:b> + * <a:b> -- nesting level 1 + * </a:b> + * </e:f> + * </c:d> + * </a:b> + * </g:h> + * + * @return Custom tag's nesting level + */ + private int computeCustomNestingLevel() { + int n = 0; + Node p = parent; + while (p != null) { + if ((p instanceof Node.CustomTag) + && name.equals(((Node.CustomTag) p).name)) { + n++; + } + p = p.parent; + } + return n; + } } /** Index: src/share/org/apache/jasper/compiler/Parser.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Parser.java,v retrieving revision 1.4 diff -u -r1.4 Parser.java --- src/share/org/apache/jasper/compiler/Parser.java 7 Jun 2002 20:04:27 -0000 1.4 +++ src/share/org/apache/jasper/compiler/Parser.java 12 Jun 2002 21:49:24 -0000 @@ -704,7 +704,8 @@ reader.reset(start); return false; } - if (tagLibInfo.getTag(shortTagName) == null) { + TagInfo tagInfo = tagLibInfo.getTag(shortTagName); + if (tagInfo == null) { err.jspError(start, "jsp.error.bad_tag", shortTagName, prefix); } @@ -716,7 +717,7 @@ if (reader.matches("/>")) { // EmptyElemTag ::= '<' Name ( S Attribute )* S? '/>'# new Node.CustomTag(attrs, start, tagName, prefix, shortTagName, - parent); + tagInfo, parent); return true; } @@ -729,10 +730,10 @@ // Looking for a body, it still can be empty; but if there is a // a tag body, its syntax would be dependent on the type of // body content declared in TLD. - String bc = ((TagLibraryInfo) taglibs.get(prefix)).getTag(shortTagName).getBodyContent(); + String bc = tagInfo.getBodyContent(); Node tagNode = new Node.CustomTag(attrs, start, tagName, prefix, - shortTagName, parent); + shortTagName, tagInfo, parent); // There are 3 body content types: empty, jsp, or tag-dependent. if (bc.equalsIgnoreCase(TagInfo.BODY_CONTENT_EMPTY)) { if (!reader.matchesETag(tagName)) { cvs server: Diffing src/share/org/apache/jasper/core cvs server: Diffing src/share/org/apache/jasper/logging cvs server: Diffing src/share/org/apache/jasper/resources cvs server: Diffing src/share/org/apache/jasper/runtime cvs server: Diffing src/share/org/apache/jasper/servlet cvs server: Diffing src/share/org/apache/jasper/util cvs server: Diffing src/share/org/apache/jasper/xmlparser
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>