| /* |
| * Copyright 1999,2004 The Apache Software Foundation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.jasper.compiler; |
| |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Vector; |
| import java.util.ArrayList; |
| |
| import javax.servlet.jsp.tagext.BodyTag; |
| import javax.servlet.jsp.tagext.DynamicAttributes; |
| import javax.servlet.jsp.tagext.IterationTag; |
| import javax.servlet.jsp.tagext.SimpleTag; |
| import javax.servlet.jsp.tagext.TagAttributeInfo; |
| import javax.servlet.jsp.tagext.TagData; |
| import javax.servlet.jsp.tagext.TagFileInfo; |
| import javax.servlet.jsp.tagext.TagInfo; |
| import javax.servlet.jsp.tagext.TagVariableInfo; |
| import javax.servlet.jsp.tagext.TryCatchFinally; |
| import javax.servlet.jsp.tagext.VariableInfo; |
| |
| import org.apache.jasper.JasperException; |
| import org.apache.jasper.compiler.tagplugin.TagPluginContext; |
| import org.xml.sax.Attributes; |
| |
| |
| /** |
| * An internal data representation of a JSP page or a JSP docuement (XML). |
| * Also included here is a visitor class for tranversing nodes. |
| * |
| * @author Kin-man Chung |
| * @author Jan Luehe |
| * @author Shawn Bayern |
| * @author Mark Roth |
| */ |
| |
| abstract class Node implements TagConstants { |
| |
| private static final VariableInfo[] ZERO_VARIABLE_INFO = { }; |
| |
| protected Attributes attrs; |
| |
| // xmlns attributes that represent tag libraries (only in XML syntax) |
| protected Attributes taglibAttrs; |
| |
| /* |
| * xmlns attributes that do not represent tag libraries |
| * (only in XML syntax) |
| */ |
| protected Attributes nonTaglibXmlnsAttrs; |
| |
| protected Nodes body; |
| protected String text; |
| protected Mark startMark; |
| protected int beginJavaLine; |
| protected int endJavaLine; |
| protected Node parent; |
| protected Nodes namedAttributeNodes; // cached for performance |
| protected String qName; |
| protected String localName; |
| /* |
| * The name of the inner class to which the codes for this node and |
| * its body are generated. For instance, for <jsp:body> in foo.jsp, |
| * this is "foo_jspHelper". This is primarily used for communicating |
| * such info from Generator to Smap generator. |
| */ |
| protected String innerClassName; |
| |
| private boolean isDummy; |
| |
| /** |
| * Zero-arg Constructor. |
| */ |
| public Node() { |
| this.isDummy = true; |
| } |
| |
| /** |
| * Constructor. |
| * |
| * @param start The location of the jsp page |
| * @param parent The enclosing node |
| */ |
| public Node(Mark start, Node parent) { |
| this.startMark = start; |
| this.isDummy = (start == null); |
| addToParent(parent); |
| } |
| |
| /** |
| * Constructor. |
| * |
| * @param qName The action's qualified name |
| * @param localName The action's local name |
| * @param start The location of the jsp page |
| * @param parent The enclosing node |
| */ |
| public Node(String qName, String localName, Mark start, Node parent) { |
| this.qName = qName; |
| this.localName = localName; |
| this.startMark = start; |
| this.isDummy = (start == null); |
| addToParent(parent); |
| } |
| |
| /** |
| * Constructor for Nodes parsed from standard syntax. |
| * |
| * @param qName The action's qualified name |
| * @param localName The action's local name |
| * @param attrs The attributes for this node |
| * @param start The location of the jsp page |
| * @param parent The enclosing node |
| */ |
| public Node(String qName, String localName, Attributes attrs, Mark start, |
| Node parent) { |
| this.qName = qName; |
| this.localName = localName; |
| this.attrs = attrs; |
| this.startMark = start; |
| this.isDummy = (start == null); |
| addToParent(parent); |
| } |
| |
| /** |
| * Constructor for Nodes parsed from XML syntax. |
| * |
| * @param qName The action's qualified name |
| * @param localName The action's local name |
| * @param attrs The action's attributes whose name does not start with |
| * xmlns |
| * @param nonTaglibXmlnsAttrs The action's xmlns attributes that do not |
| * represent tag libraries |
| * @param taglibAttrs The action's xmlns attributes that represent tag |
| * libraries |
| * @param start The location of the jsp page |
| * @param parent The enclosing node |
| */ |
| public Node(String qName, String localName, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, |
| Mark start, Node parent) { |
| this.qName = qName; |
| this.localName = localName; |
| this.attrs = attrs; |
| this.nonTaglibXmlnsAttrs = nonTaglibXmlnsAttrs; |
| this.taglibAttrs = taglibAttrs; |
| this.startMark = start; |
| this.isDummy = (start == null); |
| addToParent(parent); |
| } |
| |
| /* |
| * Constructor. |
| * |
| * @param qName The action's qualified name |
| * @param localName The action's local name |
| * @param text The text associated with this node |
| * @param start The location of the jsp page |
| * @param parent The enclosing node |
| */ |
| public Node(String qName, String localName, String text, Mark start, |
| Node parent) { |
| this.qName = qName; |
| this.localName = localName; |
| this.text = text; |
| this.startMark = start; |
| this.isDummy = (start == null); |
| addToParent(parent); |
| } |
| |
| public String getQName() { |
| return this.qName; |
| } |
| |
| public String getLocalName() { |
| return this.localName; |
| } |
| |
| /* |
| * Gets this Node's attributes. |
| * |
| * In the case of a Node parsed from standard syntax, this method returns |
| * all the Node's attributes. |
| * |
| * In the case of a Node parsed from XML syntax, this method returns only |
| * those attributes whose name does not start with xmlns. |
| */ |
| public Attributes getAttributes() { |
| return this.attrs; |
| } |
| |
| /* |
| * Gets this Node's xmlns attributes that represent tag libraries |
| * (only meaningful for Nodes parsed from XML syntax) |
| */ |
| public Attributes getTaglibAttributes() { |
| return this.taglibAttrs; |
| } |
| |
| /* |
| * Gets this Node's xmlns attributes that do not represent tag libraries |
| * (only meaningful for Nodes parsed from XML syntax) |
| */ |
| public Attributes getNonTaglibXmlnsAttributes() { |
| return this.nonTaglibXmlnsAttrs; |
| } |
| |
| public void setAttributes(Attributes attrs) { |
| this.attrs = attrs; |
| } |
| |
| public String getAttributeValue(String name) { |
| return (attrs == null) ? null : attrs.getValue(name); |
| } |
| |
| /** |
| * Get the attribute that is non request time expression, either |
| * from the attribute of the node, or from a jsp:attrbute |
| */ |
| public String getTextAttribute(String name) { |
| |
| String attr = getAttributeValue(name); |
| if (attr != null) { |
| return attr; |
| } |
| |
| NamedAttribute namedAttribute = getNamedAttributeNode(name); |
| if (namedAttribute == null) { |
| return null; |
| } |
| |
| return namedAttribute.getText(); |
| } |
| |
| /** |
| * Searches all subnodes of this node for jsp:attribute standard |
| * actions with the given name, and returns the NamedAttribute node |
| * of the matching named attribute, nor null if no such node is found. |
| * <p> |
| * This should always be called and only be called for nodes that |
| * accept dynamic runtime attribute expressions. |
| */ |
| public NamedAttribute getNamedAttributeNode( String name ) { |
| NamedAttribute result = null; |
| |
| // Look for the attribute in NamedAttribute children |
| Nodes nodes = getNamedAttributeNodes(); |
| int numChildNodes = nodes.size(); |
| for( int i = 0; i < numChildNodes; i++ ) { |
| NamedAttribute na = (NamedAttribute)nodes.getNode( i ); |
| boolean found = false; |
| int index = name.indexOf(':'); |
| if (index != -1) { |
| // qualified name |
| found = na.getName().equals(name); |
| } else { |
| found = na.getLocalName().equals(name); |
| } |
| if (found) { |
| result = na; |
| break; |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Searches all subnodes of this node for jsp:attribute standard |
| * actions, and returns that set of nodes as a Node.Nodes object. |
| * |
| * @return Possibly empty Node.Nodes object containing any jsp:attribute |
| * subnodes of this Node |
| */ |
| public Node.Nodes getNamedAttributeNodes() { |
| |
| if (namedAttributeNodes != null) { |
| return namedAttributeNodes; |
| } |
| |
| Node.Nodes result = new Node.Nodes(); |
| |
| // Look for the attribute in NamedAttribute children |
| Nodes nodes = getBody(); |
| if( nodes != null ) { |
| int numChildNodes = nodes.size(); |
| for( int i = 0; i < numChildNodes; i++ ) { |
| Node n = nodes.getNode( i ); |
| if( n instanceof NamedAttribute ) { |
| result.add( n ); |
| } |
| else if (! (n instanceof Comment)) { |
| // Nothing can come before jsp:attribute, and only |
| // jsp:body can come after it. |
| break; |
| } |
| } |
| } |
| |
| namedAttributeNodes = result; |
| return result; |
| } |
| |
| public Nodes getBody() { |
| return body; |
| } |
| |
| public void setBody(Nodes body) { |
| this.body = body; |
| } |
| |
| public String getText() { |
| return text; |
| } |
| |
| public Mark getStart() { |
| return startMark; |
| } |
| |
| public Node getParent() { |
| return parent; |
| } |
| |
| public int getBeginJavaLine() { |
| return beginJavaLine; |
| } |
| |
| public void setBeginJavaLine(int begin) { |
| beginJavaLine = begin; |
| } |
| |
| public int getEndJavaLine() { |
| return endJavaLine; |
| } |
| |
| public void setEndJavaLine(int end) { |
| endJavaLine = end; |
| } |
| |
| public boolean isDummy() { |
| return isDummy; |
| } |
| |
| public Node.Root getRoot() { |
| Node n = this; |
| while (!(n instanceof Node.Root)) { |
| n = n.getParent(); |
| } |
| return (Node.Root) n; |
| } |
| |
| public String getInnerClassName() { |
| return innerClassName; |
| } |
| |
| public void setInnerClassName(String icn) { |
| innerClassName = icn; |
| } |
| |
| /** |
| * Selects and invokes a method in the visitor class based on the node |
| * type. This is abstract and should be overrode by the extending classes. |
| * @param v The visitor class |
| */ |
| abstract void accept(Visitor v) throws JasperException; |
| |
| |
| //********************************************************************* |
| // Private utility methods |
| |
| /* |
| * Adds this Node to the body of the given parent. |
| */ |
| private void addToParent(Node parent) { |
| if (parent != null) { |
| this.parent = parent; |
| Nodes parentBody = parent.getBody(); |
| if (parentBody == null) { |
| parentBody = new Nodes(); |
| parent.setBody(parentBody); |
| } |
| parentBody.add(this); |
| } |
| } |
| |
| |
| /********************************************************************* |
| * Child classes |
| */ |
| |
| /** |
| * Represents the root of a Jsp page or Jsp document |
| */ |
| public static class Root extends Node { |
| |
| private Root parentRoot; |
| private boolean isXmlSyntax; |
| |
| // Source encoding of the page containing this Root |
| private String pageEnc; |
| |
| // Page encoding specified in JSP config element |
| private String jspConfigPageEnc; |
| |
| /* |
| * Flag indicating if the default page encoding is being used (only |
| * applicable with standard syntax). |
| * |
| * True if the page does not provide a page directive with a |
| * 'contentType' attribute (or the 'contentType' attribute doesn't |
| * have a CHARSET value), the page does not provide a page directive |
| * with a 'pageEncoding' attribute, and there is no JSP configuration |
| * element page-encoding whose URL pattern matches the page. |
| */ |
| private boolean isDefaultPageEncoding; |
| |
| /* |
| * Indicates whether an encoding has been explicitly specified in the |
| * page's XML prolog (only used for pages in XML syntax). |
| * This information is used to decide whether a translation error must |
| * be reported for encoding conflicts. |
| */ |
| private boolean isEncodingSpecifiedInProlog; |
| |
| /* |
| * Constructor. |
| */ |
| Root(Mark start, Node parent, boolean isXmlSyntax) { |
| super(start, parent); |
| this.isXmlSyntax = isXmlSyntax; |
| this.qName = JSP_ROOT_ACTION; |
| this.localName = ROOT_ACTION; |
| |
| // Figure out and set the parent root |
| Node r = parent; |
| while ((r != null) && !(r instanceof Node.Root)) |
| r = r.getParent(); |
| parentRoot = (Node.Root) r; |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| |
| public boolean isXmlSyntax() { |
| return isXmlSyntax; |
| } |
| |
| /* |
| * Sets the encoding specified in the JSP config element whose URL |
| * pattern matches the page containing this Root. |
| */ |
| public void setJspConfigPageEncoding(String enc) { |
| jspConfigPageEnc = enc; |
| } |
| |
| /* |
| * Gets the encoding specified in the JSP config element whose URL |
| * pattern matches the page containing this Root. |
| */ |
| public String getJspConfigPageEncoding() { |
| return jspConfigPageEnc; |
| } |
| |
| public void setPageEncoding(String enc) { |
| pageEnc = enc; |
| } |
| |
| public String getPageEncoding() { |
| return pageEnc; |
| } |
| |
| public void setIsDefaultPageEncoding(boolean isDefault) { |
| isDefaultPageEncoding = isDefault; |
| } |
| |
| public boolean isDefaultPageEncoding() { |
| return isDefaultPageEncoding; |
| } |
| |
| public void setIsEncodingSpecifiedInProlog(boolean isSpecified) { |
| isEncodingSpecifiedInProlog = isSpecified; |
| } |
| |
| public boolean isEncodingSpecifiedInProlog() { |
| return isEncodingSpecifiedInProlog; |
| } |
| |
| /** |
| * @return The enclosing root to this Root. Usually represents the |
| * page that includes this one. |
| */ |
| public Root getParentRoot() { |
| return parentRoot; |
| } |
| } |
| |
| /** |
| * Represents the root of a Jsp document (XML syntax) |
| */ |
| public static class JspRoot extends Node { |
| |
| public JspRoot(String qName, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, |
| Mark start, Node parent) { |
| super(qName, ROOT_ACTION, attrs, nonTaglibXmlnsAttrs, taglibAttrs, |
| start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| } |
| |
| /** |
| * Represents a page directive |
| */ |
| public static class PageDirective extends Node { |
| |
| private Vector imports; |
| |
| public PageDirective(Attributes attrs, Mark start, Node parent) { |
| this(JSP_PAGE_DIRECTIVE_ACTION, attrs, null, null, start, parent); |
| } |
| |
| public PageDirective(String qName, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, Mark start, Node parent) { |
| super(qName, PAGE_DIRECTIVE_ACTION, attrs, nonTaglibXmlnsAttrs, |
| taglibAttrs, start, parent); |
| imports = new Vector(); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| |
| /** |
| * Parses the comma-separated list of class or package names in the |
| * given attribute value and adds each component to this |
| * PageDirective's vector of imported classes and packages. |
| * @param value A comma-separated string of imports. |
| */ |
| public void addImport(String value) { |
| int start = 0; |
| int index; |
| while ((index = value.indexOf(',', start)) != -1) { |
| imports.add(value.substring(start, index).trim()); |
| start = index + 1; |
| } |
| if (start == 0) { |
| // No comma found |
| imports.add(value.trim()); |
| } else { |
| imports.add(value.substring(start).trim()); |
| } |
| } |
| |
| public List getImports() { |
| return imports; |
| } |
| } |
| |
| /** |
| * Represents an include directive |
| */ |
| public static class IncludeDirective extends Node { |
| |
| public IncludeDirective(Attributes attrs, Mark start, Node parent) { |
| this(JSP_INCLUDE_DIRECTIVE_ACTION, attrs, null, null, start, |
| parent); |
| } |
| |
| public IncludeDirective(String qName, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, Mark start, |
| Node parent) { |
| super(qName, INCLUDE_DIRECTIVE_ACTION, attrs, nonTaglibXmlnsAttrs, |
| taglibAttrs, start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| } |
| |
| /** |
| * Represents a custom taglib directive |
| */ |
| public static class TaglibDirective extends Node { |
| |
| public TaglibDirective(Attributes attrs, Mark start, Node parent) { |
| super(JSP_TAGLIB_DIRECTIVE_ACTION, TAGLIB_DIRECTIVE_ACTION, attrs, |
| start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| } |
| |
| /** |
| * Represents a tag directive |
| */ |
| public static class TagDirective extends Node { |
| private Vector imports; |
| |
| public TagDirective(Attributes attrs, Mark start, Node parent) { |
| this(JSP_TAG_DIRECTIVE_ACTION, attrs, null, null, start, parent); |
| } |
| |
| public TagDirective(String qName, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, Mark start, Node parent) { |
| super(qName, TAG_DIRECTIVE_ACTION, attrs, nonTaglibXmlnsAttrs, |
| taglibAttrs, start, parent); |
| imports = new Vector(); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| |
| /** |
| * Parses the comma-separated list of class or package names in the |
| * given attribute value and adds each component to this |
| * PageDirective's vector of imported classes and packages. |
| * @param value A comma-separated string of imports. |
| */ |
| public void addImport(String value) { |
| int start = 0; |
| int index; |
| while ((index = value.indexOf(',', start)) != -1) { |
| imports.add(value.substring(start, index).trim()); |
| start = index + 1; |
| } |
| if (start == 0) { |
| // No comma found |
| imports.add(value.trim()); |
| } else { |
| imports.add(value.substring(start).trim()); |
| } |
| } |
| |
| public List getImports() { |
| return imports; |
| } |
| } |
| |
| /** |
| * Represents an attribute directive |
| */ |
| public static class AttributeDirective extends Node { |
| |
| public AttributeDirective(Attributes attrs, Mark start, Node parent) { |
| this(JSP_ATTRIBUTE_DIRECTIVE_ACTION, attrs, null, null, start, |
| parent); |
| } |
| |
| public AttributeDirective(String qName, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, Mark start, |
| Node parent) { |
| super(qName, ATTRIBUTE_DIRECTIVE_ACTION, attrs, |
| nonTaglibXmlnsAttrs, taglibAttrs, start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| } |
| |
| /** |
| * Represents a variable directive |
| */ |
| public static class VariableDirective extends Node { |
| |
| public VariableDirective(Attributes attrs, Mark start, Node parent) { |
| this(JSP_VARIABLE_DIRECTIVE_ACTION, attrs, null, null, start, |
| parent); |
| } |
| |
| public VariableDirective(String qName, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, |
| Mark start, Node parent) { |
| super(qName, VARIABLE_DIRECTIVE_ACTION, attrs, nonTaglibXmlnsAttrs, |
| taglibAttrs, start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| } |
| |
| /** |
| * Represents a <jsp:invoke> tag file action |
| */ |
| public static class InvokeAction extends Node { |
| |
| public InvokeAction(Attributes attrs, Mark start, Node parent) { |
| this(JSP_INVOKE_ACTION, attrs, null, null, start, parent); |
| } |
| |
| public InvokeAction(String qName, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, Mark start, Node parent) { |
| super(qName, INVOKE_ACTION, attrs, nonTaglibXmlnsAttrs, |
| taglibAttrs, start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| } |
| |
| /** |
| * Represents a <jsp:doBody> tag file action |
| */ |
| public static class DoBodyAction extends Node { |
| |
| public DoBodyAction(Attributes attrs, Mark start, Node parent) { |
| this(JSP_DOBODY_ACTION, attrs, null, null, start, parent); |
| } |
| |
| public DoBodyAction(String qName, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, Mark start, Node parent) { |
| super(qName, DOBODY_ACTION, attrs, nonTaglibXmlnsAttrs, |
| taglibAttrs, start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| } |
| |
| /** |
| * Represents a Jsp comment |
| * Comments are kept for completeness. |
| */ |
| public static class Comment extends Node { |
| |
| public Comment(String text, Mark start, Node parent) { |
| super(null, null, text, start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| } |
| |
| /** |
| * Represents an expression, declaration, or scriptlet |
| */ |
| public static abstract class ScriptingElement extends Node { |
| |
| public ScriptingElement(String qName, String localName, String text, |
| Mark start, Node parent) { |
| super(qName, localName, text, start, parent); |
| } |
| |
| public ScriptingElement(String qName, String localName, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, Mark start, |
| Node parent) { |
| super(qName, localName, null, nonTaglibXmlnsAttrs, taglibAttrs, |
| start, parent); |
| } |
| |
| /** |
| * When this node was created from a JSP page in JSP syntax, its text |
| * was stored as a String in the "text" field, whereas when this node |
| * was created from a JSP document, its text was stored as one or more |
| * TemplateText nodes in its body. This method handles either case. |
| * @return The text string |
| */ |
| public String getText() { |
| String ret = text; |
| if ((ret == null) && (body != null)) { |
| StringBuffer buf = new StringBuffer(); |
| for (int i=0; i<body.size(); i++) { |
| buf.append(body.getNode(i).getText()); |
| } |
| ret = buf.toString(); |
| } |
| return ret; |
| } |
| |
| /** |
| * For the same reason as above, the source line information in the |
| * contained TemplateText node should be used. |
| */ |
| public Mark getStart() { |
| if (text == null && body != null && body.size() > 0) { |
| return body.getNode(0).getStart(); |
| } else { |
| return super.getStart(); |
| } |
| } |
| } |
| |
| /** |
| * Represents a declaration |
| */ |
| public static class Declaration extends ScriptingElement { |
| |
| public Declaration(String text, Mark start, Node parent) { |
| super(JSP_DECLARATION_ACTION, DECLARATION_ACTION, text, start, |
| parent); |
| } |
| |
| public Declaration(String qName, Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, Mark start, |
| Node parent) { |
| super(qName, DECLARATION_ACTION, nonTaglibXmlnsAttrs, |
| taglibAttrs, start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| } |
| |
| /** |
| * Represents an expression. Expressions in attributes are embedded |
| * in the attribute string and not here. |
| */ |
| public static class Expression extends ScriptingElement { |
| |
| public Expression(String text, Mark start, Node parent) { |
| super(JSP_EXPRESSION_ACTION, EXPRESSION_ACTION, text, start, |
| parent); |
| } |
| |
| public Expression(String qName, Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, Mark start, |
| Node parent) { |
| super(qName, EXPRESSION_ACTION, nonTaglibXmlnsAttrs, taglibAttrs, |
| start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| } |
| |
| /** |
| * Represents a scriptlet |
| */ |
| public static class Scriptlet extends ScriptingElement { |
| |
| public Scriptlet(String text, Mark start, Node parent) { |
| super(JSP_SCRIPTLET_ACTION, SCRIPTLET_ACTION, text, start, parent); |
| } |
| |
| public Scriptlet(String qName, Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, Mark start, |
| Node parent) { |
| super(qName, SCRIPTLET_ACTION, nonTaglibXmlnsAttrs, taglibAttrs, |
| start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| } |
| |
| /** |
| * Represents an EL expression. Expressions in attributes are embedded |
| * in the attribute string and not here. |
| */ |
| public static class ELExpression extends Node { |
| |
| private ELNode.Nodes el; |
| |
| public ELExpression(String text, Mark start, Node parent) { |
| super(null, null, text, start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| |
| public void setEL(ELNode.Nodes el) { |
| this.el = el; |
| } |
| |
| public ELNode.Nodes getEL() { |
| return el; |
| } |
| } |
| |
| /** |
| * Represents a param action |
| */ |
| public static class ParamAction extends Node { |
| |
| JspAttribute value; |
| |
| public ParamAction(Attributes attrs, Mark start, Node parent) { |
| this(JSP_PARAM_ACTION, attrs, null, null, start, parent); |
| } |
| |
| public ParamAction(String qName, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, Mark start, Node parent) { |
| super(qName, PARAM_ACTION, attrs, nonTaglibXmlnsAttrs, |
| taglibAttrs, start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| |
| public void setValue(JspAttribute value) { |
| this.value = value; |
| } |
| |
| public JspAttribute getValue() { |
| return value; |
| } |
| } |
| |
| /** |
| * Represents a params action |
| */ |
| public static class ParamsAction extends Node { |
| |
| public ParamsAction(Mark start, Node parent) { |
| this(JSP_PARAMS_ACTION, null, null, start, parent); |
| } |
| |
| public ParamsAction(String qName, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, |
| Mark start, Node parent) { |
| super(qName, PARAMS_ACTION, null, nonTaglibXmlnsAttrs, taglibAttrs, |
| start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| } |
| |
| /** |
| * Represents a fallback action |
| */ |
| public static class FallBackAction extends Node { |
| |
| public FallBackAction(Mark start, Node parent) { |
| this(JSP_FALLBACK_ACTION, null, null, start, parent); |
| } |
| |
| public FallBackAction(String qName, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, Mark start, |
| Node parent) { |
| super(qName, FALLBACK_ACTION, null, nonTaglibXmlnsAttrs, |
| taglibAttrs, start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| } |
| |
| /** |
| * Represents an include action |
| */ |
| public static class IncludeAction extends Node { |
| |
| private JspAttribute page; |
| |
| public IncludeAction(Attributes attrs, Mark start, Node parent) { |
| this(JSP_INCLUDE_ACTION, attrs, null, null, start, parent); |
| } |
| |
| public IncludeAction(String qName, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, Mark start, Node parent) { |
| super(qName, INCLUDE_ACTION, attrs, nonTaglibXmlnsAttrs, |
| taglibAttrs, start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| |
| public void setPage(JspAttribute page) { |
| this.page = page; |
| } |
| |
| public JspAttribute getPage() { |
| return page; |
| } |
| } |
| |
| /** |
| * Represents a forward action |
| */ |
| public static class ForwardAction extends Node { |
| |
| private JspAttribute page; |
| |
| public ForwardAction(Attributes attrs, Mark start, Node parent) { |
| this(JSP_FORWARD_ACTION, attrs, null, null, start, parent); |
| } |
| |
| public ForwardAction(String qName, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, Mark start, Node parent) { |
| super(qName, FORWARD_ACTION, attrs, nonTaglibXmlnsAttrs, |
| taglibAttrs, start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| |
| public void setPage(JspAttribute page) { |
| this.page = page; |
| } |
| |
| public JspAttribute getPage() { |
| return page; |
| } |
| } |
| |
| /** |
| * Represents a getProperty action |
| */ |
| public static class GetProperty extends Node { |
| |
| public GetProperty(Attributes attrs, Mark start, Node parent) { |
| this(JSP_GET_PROPERTY_ACTION, attrs, null, null, start, parent); |
| } |
| |
| public GetProperty(String qName, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, Mark start, Node parent) { |
| super(qName, GET_PROPERTY_ACTION, attrs, nonTaglibXmlnsAttrs, |
| taglibAttrs, start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| } |
| |
| /** |
| * Represents a setProperty action |
| */ |
| public static class SetProperty extends Node { |
| |
| private JspAttribute value; |
| |
| public SetProperty(Attributes attrs, Mark start, Node parent) { |
| this(JSP_SET_PROPERTY_ACTION, attrs, null, null, start, parent); |
| } |
| |
| public SetProperty(String qName, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, Mark start, Node parent) { |
| super(qName, SET_PROPERTY_ACTION, attrs, nonTaglibXmlnsAttrs, |
| taglibAttrs, start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| |
| public void setValue(JspAttribute value) { |
| this.value = value; |
| } |
| |
| public JspAttribute getValue() { |
| return value; |
| } |
| } |
| |
| /** |
| * Represents a useBean action |
| */ |
| public static class UseBean extends Node { |
| |
| JspAttribute beanName; |
| |
| public UseBean(Attributes attrs, Mark start, Node parent) { |
| this(JSP_USE_BEAN_ACTION, attrs, null, null, start, parent); |
| } |
| |
| public UseBean(String qName, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, |
| Mark start, Node parent) { |
| super(qName, USE_BEAN_ACTION, attrs, nonTaglibXmlnsAttrs, |
| taglibAttrs, start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| |
| public void setBeanName(JspAttribute beanName) { |
| this.beanName = beanName; |
| } |
| |
| public JspAttribute getBeanName() { |
| return beanName; |
| } |
| } |
| |
| /** |
| * Represents a plugin action |
| */ |
| public static class PlugIn extends Node { |
| |
| private JspAttribute width; |
| private JspAttribute height; |
| |
| public PlugIn(Attributes attrs, Mark start, Node parent) { |
| this(JSP_PLUGIN_ACTION, attrs, null, null, start, parent); |
| } |
| |
| public PlugIn(String qName, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, |
| Mark start, Node parent) { |
| super(qName, PLUGIN_ACTION, attrs, nonTaglibXmlnsAttrs, |
| taglibAttrs, start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| |
| public void setHeight(JspAttribute height) { |
| this.height = height; |
| } |
| |
| public void setWidth(JspAttribute width) { |
| this.width = width; |
| } |
| |
| public JspAttribute getHeight() { |
| return height; |
| } |
| |
| public JspAttribute getWidth() { |
| return width; |
| } |
| } |
| |
| /** |
| * Represents an uninterpreted tag, from a Jsp document |
| */ |
| public static class UninterpretedTag extends Node { |
| |
| private JspAttribute[] jspAttrs; |
| |
| public UninterpretedTag(String qName, String localName, |
| Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, |
| Mark start, Node parent) { |
| super(qName, localName, attrs, nonTaglibXmlnsAttrs, taglibAttrs, |
| start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| |
| public void setJspAttributes(JspAttribute[] jspAttrs) { |
| this.jspAttrs = jspAttrs; |
| } |
| |
| public JspAttribute[] getJspAttributes() { |
| return jspAttrs; |
| } |
| } |
| |
| /** |
| * Represents a <jsp:element>. |
| */ |
| public static class JspElement extends Node { |
| |
| private JspAttribute[] jspAttrs; |
| private JspAttribute nameAttr; |
| |
| public JspElement(Attributes attrs, Mark start, Node parent) { |
| this(JSP_ELEMENT_ACTION, attrs, null, null, start, parent); |
| } |
| |
| public JspElement(String qName, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, Mark start, Node parent) { |
| super(qName, ELEMENT_ACTION, attrs, nonTaglibXmlnsAttrs, |
| taglibAttrs, start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| |
| public void setJspAttributes(JspAttribute[] jspAttrs) { |
| this.jspAttrs = jspAttrs; |
| } |
| |
| public JspAttribute[] getJspAttributes() { |
| return jspAttrs; |
| } |
| |
| /* |
| * Sets the XML-style 'name' attribute |
| */ |
| public void setNameAttribute(JspAttribute nameAttr) { |
| this.nameAttr = nameAttr; |
| } |
| |
| /* |
| * Gets the XML-style 'name' attribute |
| */ |
| public JspAttribute getNameAttribute() { |
| return this.nameAttr; |
| } |
| } |
| |
| /** |
| * Represents a <jsp:output>. |
| */ |
| public static class JspOutput extends Node { |
| |
| public JspOutput(String qName, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, |
| Mark start, Node parent) { |
| super(qName, OUTPUT_ACTION, attrs, nonTaglibXmlnsAttrs, |
| taglibAttrs, start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| } |
| |
| /** |
| * Collected information about child elements. Used by nodes like |
| * CustomTag, JspBody, and NamedAttribute. The information is |
| * set in the Collector. |
| */ |
| public static class ChildInfo { |
| private boolean scriptless; // true if the tag and its body |
| // contain no scripting elements. |
| private boolean hasUseBean; |
| private boolean hasIncludeAction; |
| private boolean hasParamAction; |
| private boolean hasSetProperty; |
| private boolean hasScriptingVars; |
| |
| public void setScriptless(boolean s) { |
| scriptless = s; |
| } |
| |
| public boolean isScriptless() { |
| return scriptless; |
| } |
| |
| public void setHasUseBean(boolean u) { |
| hasUseBean = u; |
| } |
| |
| public boolean hasUseBean() { |
| return hasUseBean; |
| } |
| |
| public void setHasIncludeAction(boolean i) { |
| hasIncludeAction = i; |
| } |
| |
| public boolean hasIncludeAction() { |
| return hasIncludeAction; |
| } |
| |
| public void setHasParamAction(boolean i) { |
| hasParamAction = i; |
| } |
| |
| public boolean hasParamAction() { |
| return hasParamAction; |
| } |
| |
| public void setHasSetProperty(boolean s) { |
| hasSetProperty = s; |
| } |
| |
| public boolean hasSetProperty() { |
| return hasSetProperty; |
| } |
| |
| public void setHasScriptingVars(boolean s) { |
| hasScriptingVars = s; |
| } |
| |
| public boolean hasScriptingVars() { |
| return hasScriptingVars; |
| } |
| } |
| |
| /** |
| * Represents a custom tag |
| */ |
| public static class CustomTag extends Node { |
| |
| private String uri; |
| private String prefix; |
| private JspAttribute[] jspAttrs; |
| private TagData tagData; |
| private String tagHandlerPoolName; |
| private TagInfo tagInfo; |
| private TagFileInfo tagFileInfo; |
| private Class tagHandlerClass; |
| private VariableInfo[] varInfos; |
| private int customNestingLevel; |
| private ChildInfo childInfo; |
| private boolean implementsIterationTag; |
| private boolean implementsBodyTag; |
| private boolean implementsTryCatchFinally; |
| private boolean implementsSimpleTag; |
| private boolean implementsDynamicAttributes; |
| private Vector atBeginScriptingVars; |
| private Vector atEndScriptingVars; |
| private Vector nestedScriptingVars; |
| private Node.CustomTag customTagParent; |
| private Integer numCount; |
| private boolean useTagPlugin; |
| private TagPluginContext tagPluginContext; |
| |
| /** |
| * The following two fields are used for holding the Java |
| * scriptlets that the tag plugins may generate. Meaningful |
| * only if useTagPlugin is true; |
| * Could move them into TagPluginContextImpl, but we'll need |
| * to cast tagPluginContext to TagPluginContextImpl all the time... |
| */ |
| private Nodes atSTag; |
| private Nodes atETag; |
| |
| /* |
| * Constructor for custom action implemented by tag handler. |
| */ |
| public CustomTag(String qName, String prefix, String localName, |
| String uri, Attributes attrs, Mark start, Node parent, |
| TagInfo tagInfo, Class tagHandlerClass) { |
| this(qName, prefix, localName, uri, attrs, null, null, start, |
| parent, tagInfo, tagHandlerClass); |
| } |
| |
| /* |
| * Constructor for custom action implemented by tag handler. |
| */ |
| public CustomTag(String qName, String prefix, String localName, |
| String uri, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, |
| Mark start, Node parent, TagInfo tagInfo, |
| Class tagHandlerClass) { |
| super(qName, localName, attrs, nonTaglibXmlnsAttrs, taglibAttrs, |
| start, parent); |
| |
| this.uri = uri; |
| this.prefix = prefix; |
| this.tagInfo = tagInfo; |
| this.tagHandlerClass = tagHandlerClass; |
| this.customNestingLevel = makeCustomNestingLevel(); |
| this.childInfo = new ChildInfo(); |
| |
| this.implementsIterationTag = |
| IterationTag.class.isAssignableFrom(tagHandlerClass); |
| this.implementsBodyTag = |
| BodyTag.class.isAssignableFrom(tagHandlerClass); |
| this.implementsTryCatchFinally = |
| TryCatchFinally.class.isAssignableFrom(tagHandlerClass); |
| this.implementsSimpleTag = |
| SimpleTag.class.isAssignableFrom(tagHandlerClass); |
| this.implementsDynamicAttributes = |
| DynamicAttributes.class.isAssignableFrom(tagHandlerClass); |
| } |
| |
| /* |
| * Constructor for custom action implemented by tag file. |
| */ |
| public CustomTag(String qName, String prefix, String localName, |
| String uri, Attributes attrs, Mark start, Node parent, |
| TagFileInfo tagFileInfo) { |
| this(qName, prefix, localName, uri, attrs, null, null, start, |
| parent, tagFileInfo); |
| } |
| |
| /* |
| * Constructor for custom action implemented by tag file. |
| */ |
| public CustomTag(String qName, String prefix, String localName, |
| String uri, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, |
| Mark start, Node parent, TagFileInfo tagFileInfo) { |
| |
| super(qName, localName, attrs, nonTaglibXmlnsAttrs, taglibAttrs, |
| start, parent); |
| |
| this.uri = uri; |
| this.prefix = prefix; |
| this.tagFileInfo = tagFileInfo; |
| this.tagInfo = tagFileInfo.getTagInfo(); |
| this.customNestingLevel = makeCustomNestingLevel(); |
| this.childInfo = new ChildInfo(); |
| |
| this.implementsIterationTag = false; |
| this.implementsBodyTag = false; |
| this.implementsTryCatchFinally = false; |
| this.implementsSimpleTag = true; |
| this.implementsDynamicAttributes = tagInfo.hasDynamicAttributes(); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| |
| /** |
| * @return The URI namespace that this custom action belongs to |
| */ |
| public String getURI() { |
| return this.uri; |
| } |
| |
| /** |
| * @return The tag prefix |
| */ |
| public String getPrefix() { |
| return prefix; |
| } |
| |
| public void setJspAttributes(JspAttribute[] jspAttrs) { |
| this.jspAttrs = jspAttrs; |
| } |
| |
| public JspAttribute[] getJspAttributes() { |
| return jspAttrs; |
| } |
| |
| public ChildInfo getChildInfo() { |
| return childInfo; |
| } |
| |
| public void setTagData(TagData tagData) { |
| this.tagData = tagData; |
| this.varInfos = tagInfo.getVariableInfo(tagData); |
| if (this.varInfos == null) { |
| this.varInfos = ZERO_VARIABLE_INFO; |
| } |
| } |
| |
| public TagData getTagData() { |
| return tagData; |
| } |
| |
| public void setTagHandlerPoolName(String s) { |
| tagHandlerPoolName = s; |
| } |
| |
| public String getTagHandlerPoolName() { |
| return tagHandlerPoolName; |
| } |
| |
| public TagInfo getTagInfo() { |
| return tagInfo; |
| } |
| |
| public TagFileInfo getTagFileInfo() { |
| return tagFileInfo; |
| } |
| |
| /* |
| * @return true if this custom action is supported by a tag file, |
| * false otherwise |
| */ |
| public boolean isTagFile() { |
| return tagFileInfo != null; |
| } |
| |
| public Class getTagHandlerClass() { |
| return tagHandlerClass; |
| } |
| |
| public void setTagHandlerClass(Class hc) { |
| tagHandlerClass = hc; |
| } |
| |
| public boolean implementsIterationTag() { |
| return implementsIterationTag; |
| } |
| |
| public boolean implementsBodyTag() { |
| return implementsBodyTag; |
| } |
| |
| public boolean implementsTryCatchFinally() { |
| return implementsTryCatchFinally; |
| } |
| |
| public boolean implementsSimpleTag() { |
| return implementsSimpleTag; |
| } |
| |
| public boolean implementsDynamicAttributes() { |
| return implementsDynamicAttributes; |
| } |
| |
| public TagVariableInfo[] getTagVariableInfos() { |
| return tagInfo.getTagVariableInfos(); |
| } |
| |
| public VariableInfo[] getVariableInfos() { |
| return varInfos; |
| } |
| |
| public void setCustomTagParent(Node.CustomTag n) { |
| this.customTagParent = n; |
| } |
| |
| public Node.CustomTag getCustomTagParent() { |
| return this.customTagParent; |
| } |
| |
| public void setNumCount(Integer count) { |
| this.numCount = count; |
| } |
| |
| public Integer getNumCount() { |
| return this.numCount; |
| } |
| |
| public void setScriptingVars(Vector vec, int scope) { |
| switch (scope) { |
| case VariableInfo.AT_BEGIN: |
| this.atBeginScriptingVars = vec; |
| break; |
| case VariableInfo.AT_END: |
| this.atEndScriptingVars = vec; |
| break; |
| case VariableInfo.NESTED: |
| this.nestedScriptingVars = vec; |
| break; |
| } |
| } |
| |
| /* |
| * Gets the scripting variables for the given scope that need to be |
| * declared. |
| */ |
| public Vector getScriptingVars(int scope) { |
| Vector vec = null; |
| |
| switch (scope) { |
| case VariableInfo.AT_BEGIN: |
| vec = this.atBeginScriptingVars; |
| break; |
| case VariableInfo.AT_END: |
| vec = this.atEndScriptingVars; |
| break; |
| case VariableInfo.NESTED: |
| vec = this.nestedScriptingVars; |
| break; |
| } |
| |
| return vec; |
| } |
| |
| /* |
| * Gets this custom tag's custom nesting level, which is given as |
| * the number of times this custom tag is nested inside itself. |
| */ |
| public int getCustomNestingLevel() { |
| return customNestingLevel; |
| } |
| |
| /** |
| * Checks to see if the attribute of the given name is of type |
| * JspFragment. |
| */ |
| public boolean checkIfAttributeIsJspFragment( String name ) { |
| boolean result = false; |
| |
| TagAttributeInfo[] attributes = tagInfo.getAttributes(); |
| for (int i = 0; i < attributes.length; i++) { |
| if (attributes[i].getName().equals(name) && |
| attributes[i].isFragment()) { |
| result = true; |
| break; |
| } |
| } |
| |
| return result; |
| } |
| |
| public void setUseTagPlugin(boolean use) { |
| useTagPlugin = use; |
| } |
| |
| public boolean useTagPlugin() { |
| return useTagPlugin; |
| } |
| |
| public void setTagPluginContext(TagPluginContext tagPluginContext) { |
| this.tagPluginContext = tagPluginContext; |
| } |
| |
| public TagPluginContext getTagPluginContext() { |
| return tagPluginContext; |
| } |
| |
| public void setAtSTag(Nodes sTag) { |
| atSTag = sTag; |
| } |
| |
| public Nodes getAtSTag() { |
| return atSTag; |
| } |
| |
| public void setAtETag(Nodes eTag) { |
| atETag = eTag; |
| } |
| |
| public Nodes getAtETag() { |
| return atETag; |
| } |
| |
| /* |
| * Computes this custom tag's custom 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 makeCustomNestingLevel() { |
| int n = 0; |
| Node p = parent; |
| while (p != null) { |
| if ((p instanceof Node.CustomTag) |
| && qName.equals(((Node.CustomTag) p).qName)) { |
| n++; |
| } |
| p = p.parent; |
| } |
| return n; |
| } |
| |
| /** |
| * Returns true if this custom action has an empty body, and false |
| * otherwise. |
| * |
| * A custom action is considered to have an empty body if the |
| * following holds true: |
| * - getBody() returns null, or |
| * - all immediate children are jsp:attribute actions, or |
| * - the action's jsp:body is empty. |
| */ |
| public boolean hasEmptyBody() { |
| boolean hasEmptyBody = true; |
| Nodes nodes = getBody(); |
| if (nodes != null) { |
| int numChildNodes = nodes.size(); |
| for (int i=0; i<numChildNodes; i++) { |
| Node n = nodes.getNode(i); |
| if (!(n instanceof NamedAttribute)) { |
| if (n instanceof JspBody) { |
| hasEmptyBody = (n.getBody() == null); |
| } else { |
| hasEmptyBody = false; |
| } |
| break; |
| } |
| } |
| } |
| |
| return hasEmptyBody; |
| } |
| } |
| |
| /** |
| * Used as a placeholder for the evaluation code of a custom action |
| * attribute (used by the tag plugin machinery only). |
| */ |
| public static class AttributeGenerator extends Node { |
| String name; // name of the attribute |
| CustomTag tag; // The tag this attribute belongs to |
| |
| public AttributeGenerator(Mark start, String name, CustomTag tag) { |
| super(start, null); |
| this.name = name; |
| this.tag = tag; |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| |
| public String getName() { |
| return name; |
| } |
| |
| public CustomTag getTag() { |
| return tag; |
| } |
| } |
| |
| /** |
| * Represents the body of a <jsp:text> element |
| */ |
| public static class JspText extends Node { |
| |
| public JspText(String qName, Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, Mark start, Node parent) { |
| super(qName, TEXT_ACTION, null, nonTaglibXmlnsAttrs, taglibAttrs, |
| start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| } |
| |
| /** |
| * Represents a Named Attribute (<jsp:attribute>) |
| */ |
| public static class NamedAttribute extends Node { |
| |
| // A unique temporary variable name suitable for code generation |
| private String temporaryVariableName; |
| |
| // True if this node is to be trimmed, or false otherwise |
| private boolean trim = true; |
| |
| private ChildInfo childInfo; |
| private String name; |
| private String localName; |
| private String prefix; |
| |
| public NamedAttribute(Attributes attrs, Mark start, Node parent) { |
| this(JSP_ATTRIBUTE_ACTION, attrs, null, null, start, parent); |
| } |
| |
| public NamedAttribute(String qName, Attributes attrs, |
| Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, |
| Mark start, Node parent) { |
| |
| super(qName, ATTRIBUTE_ACTION, attrs, nonTaglibXmlnsAttrs, |
| taglibAttrs, start, parent); |
| temporaryVariableName = JspUtil.nextTemporaryVariableName(); |
| if( "false".equals( this.getAttributeValue( "trim" ) ) ) { |
| // (if null or true, leave default of true) |
| trim = false; |
| } |
| childInfo = new ChildInfo(); |
| name = this.getAttributeValue("name"); |
| if (name != null) { |
| // Mandatary attribute "name" will be checked in Validator |
| localName = name; |
| int index = name.indexOf(':'); |
| if (index != -1) { |
| prefix = name.substring(0, index); |
| localName = name.substring(index+1); |
| } |
| } |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| |
| public String getName() { |
| return this.name; |
| } |
| |
| public String getLocalName() { |
| return this.localName; |
| } |
| |
| public String getPrefix() { |
| return this.prefix; |
| } |
| |
| public ChildInfo getChildInfo() { |
| return this.childInfo; |
| } |
| |
| public boolean isTrim() { |
| return trim; |
| } |
| |
| /** |
| * @return A unique temporary variable name to store the result in. |
| * (this probably could go elsewhere, but it's convenient here) |
| */ |
| public String getTemporaryVariableName() { |
| return temporaryVariableName; |
| } |
| |
| /* |
| * Get the attribute value from this named attribute (<jsp:attribute>). |
| * Since this method is only for attributes that are not rtexpr, |
| * we can assume the body of the jsp:attribute is a template text. |
| */ |
| public String getText() { |
| |
| class AttributeVisitor extends Visitor { |
| String attrValue = null; |
| public void visit(TemplateText txt) { |
| attrValue = new String(txt.getText()); |
| } |
| |
| public String getAttrValue() { |
| return attrValue; |
| } |
| } |
| |
| // According to JSP 2.0, if the body of the <jsp:attribute> |
| // action is empty, it is equivalent of specifying "" as the value |
| // of the attribute. |
| String text = ""; |
| if (getBody() != null) { |
| AttributeVisitor attributeVisitor = new AttributeVisitor(); |
| try { |
| getBody().visit(attributeVisitor); |
| } catch (JasperException e) { |
| } |
| text = attributeVisitor.getAttrValue(); |
| } |
| |
| return text; |
| } |
| } |
| |
| /** |
| * Represents a JspBody node (<jsp:body>) |
| */ |
| public static class JspBody extends Node { |
| |
| private ChildInfo childInfo; |
| |
| public JspBody(Mark start, Node parent) { |
| this(JSP_BODY_ACTION, null, null, start, parent); |
| } |
| |
| public JspBody(String qName, Attributes nonTaglibXmlnsAttrs, |
| Attributes taglibAttrs, Mark start, Node parent) { |
| super(qName, BODY_ACTION, null, nonTaglibXmlnsAttrs, taglibAttrs, |
| start, parent); |
| this.childInfo = new ChildInfo(); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| |
| public ChildInfo getChildInfo() { |
| return childInfo; |
| } |
| } |
| |
| /** |
| * Represents a template text string |
| */ |
| public static class TemplateText extends Node { |
| |
| private ArrayList extraSmap = null; |
| |
| public TemplateText(String text, Mark start, Node parent) { |
| super(null, null, text, start, parent); |
| } |
| |
| public void accept(Visitor v) throws JasperException { |
| v.visit(this); |
| } |
| |
| /** |
| * Trim all whitespace from the left of the template text |
| */ |
| public void ltrim() { |
| int index = 0; |
| while ((index < text.length()) && (text.charAt(index) <= ' ')) { |
| index++; |
| } |
| text = text.substring(index); |
| } |
| |
| public void setText(String text) { |
| this.text = text; |
| } |
| |
| /** |
| * Trim all whitespace from the right of the template text |
| */ |
| public void rtrim() { |
| int index = text.length(); |
| while( (index > 0) && (text.charAt(index-1) <= ' ') ) { |
| index--; |
| } |
| text = text.substring(0, index); |
| } |
| |
| /** |
| * Returns true if this template text contains whitespace only. |
| */ |
| public boolean isAllSpace() { |
| boolean isAllSpace = true; |
| for (int i=0; i<text.length(); i++) { |
| if (!Character.isWhitespace(text.charAt(i))) { |
| isAllSpace = false; |
| break; |
| } |
| } |
| return isAllSpace; |
| } |
| |
| /** |
| * Add a source to Java line mapping |
| * @param srcLine The postion of the source line, relative to the line |
| * at the start of this node. The corresponding java line is |
| * assumed to be consecutive, i.e. one more than the last. |
| */ |
| public void addSmap(int srcLine) { |
| if (extraSmap == null) { |
| extraSmap = new ArrayList(); |
| } |
| extraSmap.add(new Integer(srcLine)); |
| } |
| |
| public ArrayList getExtraSmap() { |
| return extraSmap; |
| } |
| } |
| |
| /********************************************************************* |
| * Auxillary classes used in Node |
| */ |
| |
| /** |
| * Represents attributes that can be request time expressions. |
| * |
| * Can either be a plain attribute, an attribute that represents a |
| * request time expression value, or a named attribute (specified using |
| * the jsp:attribute standard action). |
| */ |
| |
| public static class JspAttribute { |
| |
| private String qName; |
| private String uri; |
| private String localName; |
| private String value; |
| private boolean expression; |
| private boolean dynamic; |
| private ELNode.Nodes el; |
| |
| // If true, this JspAttribute represents a <jsp:attribute> |
| private boolean namedAttribute; |
| // The node in the parse tree for the NamedAttribute |
| private NamedAttribute namedAttributeNode; |
| |
| JspAttribute(String qName, String uri, String localName, String value, |
| boolean expr, ELNode.Nodes el, boolean dyn ) { |
| this.qName = qName; |
| this.uri = uri; |
| this.localName = localName; |
| this.value = value; |
| this.namedAttributeNode = null; |
| this.expression = expr; |
| this.el = el; |
| this.dynamic = dyn; |
| this.namedAttribute = false; |
| } |
| |
| /** |
| * Use this constructor if the JspAttribute represents a |
| * named attribute. In this case, we have to store the nodes of |
| * the body of the attribute. |
| */ |
| JspAttribute(NamedAttribute na, boolean dyn) { |
| this.qName = na.getName(); |
| this.localName = na.getLocalName(); |
| this.value = null; |
| this.namedAttributeNode = na; |
| this.expression = false; |
| this.el = null; |
| this.dynamic = dyn; |
| this.namedAttribute = true; |
| } |
| |
| /** |
| * @return The name of the attribute |
| */ |
| public String getName() { |
| return qName; |
| } |
| |
| /** |
| * @return The local name of the attribute |
| */ |
| public String getLocalName() { |
| return localName; |
| } |
| |
| /** |
| * @return The namespace of the attribute, or null if in the default |
| * namespace |
| */ |
| public String getURI() { |
| return uri; |
| } |
| |
| /** |
| * Only makes sense if namedAttribute is false. |
| * |
| * @return the value for the attribute, or the expression string |
| * (stripped of "<%=", "%>", "%=", or "%" |
| * but containing "${" and "}" for EL expressions) |
| */ |
| public String getValue() { |
| return value; |
| } |
| |
| /** |
| * Only makes sense if namedAttribute is true. |
| * |
| * @return the nodes that evaluate to the body of this attribute. |
| */ |
| public NamedAttribute getNamedAttributeNode() { |
| return namedAttributeNode; |
| } |
| |
| /** |
| * @return true if the value represents a traditional rtexprvalue |
| */ |
| public boolean isExpression() { |
| return expression; |
| } |
| |
| /** |
| * @return true if the value represents a NamedAttribute value. |
| */ |
| public boolean isNamedAttribute() { |
| return namedAttribute; |
| } |
| |
| /** |
| * @return true if the value represents an expression that should |
| * be fed to the expression interpreter |
| * @return false for string literals or rtexprvalues that should |
| * not be interpreted or reevaluated |
| */ |
| public boolean isELInterpreterInput() { |
| return el != null; |
| } |
| |
| /** |
| * @return true if the value is a string literal known at translation |
| * time. |
| */ |
| public boolean isLiteral() { |
| return !expression && (el != null) && !namedAttribute; |
| } |
| |
| /** |
| * XXX |
| */ |
| public boolean isDynamic() { |
| return dynamic; |
| } |
| |
| public ELNode.Nodes getEL() { |
| return el; |
| } |
| } |
| |
| /** |
| * An ordered list of Node, used to represent the body of an element, or |
| * a jsp page of jsp document. |
| */ |
| public static class Nodes { |
| |
| private List list; |
| private Node.Root root; // null if this is not a page |
| private boolean generatedInBuffer; |
| |
| public Nodes() { |
| list = new Vector(); |
| } |
| |
| public Nodes(Node.Root root) { |
| this.root = root; |
| list = new Vector(); |
| list.add(root); |
| } |
| |
| /** |
| * Appends a node to the list |
| * @param n The node to add |
| */ |
| public void add(Node n) { |
| list.add(n); |
| root = null; |
| } |
| |
| /** |
| * Removes the given node from the list. |
| * @param n The node to be removed |
| */ |
| public void remove(Node n) { |
| list.remove(n); |
| } |
| |
| /** |
| * Visit the nodes in the list with the supplied visitor |
| * @param v The visitor used |
| */ |
| public void visit(Visitor v) throws JasperException { |
| Iterator iter = list.iterator(); |
| while (iter.hasNext()) { |
| Node n = (Node) iter.next(); |
| n.accept(v); |
| } |
| } |
| |
| public int size() { |
| return list.size(); |
| } |
| |
| public Node getNode(int index) { |
| Node n = null; |
| try { |
| n = (Node) list.get(index); |
| } catch (ArrayIndexOutOfBoundsException e) { |
| } |
| return n; |
| } |
| |
| public Node.Root getRoot() { |
| return root; |
| } |
| |
| public boolean isGeneratedInBuffer() { |
| return generatedInBuffer; |
| } |
| |
| public void setGeneratedInBuffer(boolean g) { |
| generatedInBuffer = g; |
| } |
| } |
| |
| /** |
| * A visitor class for visiting the node. This class also provides the |
| * default action (i.e. nop) for each of the child class of the Node. |
| * An actual visitor should extend this class and supply the visit |
| * method for the nodes that it cares. |
| */ |
| public static class Visitor { |
| |
| /** |
| * This method provides a place to put actions that are common to |
| * all nodes. Override this in the child visitor class if need to. |
| */ |
| protected void doVisit(Node n) throws JasperException { |
| } |
| |
| /** |
| * Visit the body of a node, using the current visitor |
| */ |
| protected void visitBody(Node n) throws JasperException { |
| if (n.getBody() != null) { |
| n.getBody().visit(this); |
| } |
| } |
| |
| public void visit(Root n) throws JasperException { |
| doVisit(n); |
| visitBody(n); |
| } |
| |
| public void visit(JspRoot n) throws JasperException { |
| doVisit(n); |
| visitBody(n); |
| } |
| |
| public void visit(PageDirective n) throws JasperException { |
| doVisit(n); |
| } |
| |
| public void visit(TagDirective n) throws JasperException { |
| doVisit(n); |
| } |
| |
| public void visit(IncludeDirective n) throws JasperException { |
| doVisit(n); |
| visitBody(n); |
| } |
| |
| public void visit(TaglibDirective n) throws JasperException { |
| doVisit(n); |
| } |
| |
| public void visit(AttributeDirective n) throws JasperException { |
| doVisit(n); |
| } |
| |
| public void visit(VariableDirective n) throws JasperException { |
| doVisit(n); |
| } |
| |
| public void visit(Comment n) throws JasperException { |
| doVisit(n); |
| } |
| |
| public void visit(Declaration n) throws JasperException { |
| doVisit(n); |
| } |
| |
| public void visit(Expression n) throws JasperException { |
| doVisit(n); |
| } |
| |
| public void visit(Scriptlet n) throws JasperException { |
| doVisit(n); |
| } |
| |
| public void visit(ELExpression n) throws JasperException { |
| doVisit(n); |
| } |
| |
| public void visit(IncludeAction n) throws JasperException { |
| doVisit(n); |
| visitBody(n); |
| } |
| |
| public void visit(ForwardAction n) throws JasperException { |
| doVisit(n); |
| visitBody(n); |
| } |
| |
| public void visit(GetProperty n) throws JasperException { |
| doVisit(n); |
| visitBody(n); |
| } |
| |
| public void visit(SetProperty n) throws JasperException { |
| doVisit(n); |
| visitBody(n); |
| } |
| |
| public void visit(ParamAction n) throws JasperException { |
| doVisit(n); |
| visitBody(n); |
| } |
| |
| public void visit(ParamsAction n) throws JasperException { |
| doVisit(n); |
| visitBody(n); |
| } |
| |
| public void visit(FallBackAction n) throws JasperException { |
| doVisit(n); |
| visitBody(n); |
| } |
| |
| public void visit(UseBean n) throws JasperException { |
| doVisit(n); |
| visitBody(n); |
| } |
| |
| public void visit(PlugIn n) throws JasperException { |
| doVisit(n); |
| visitBody(n); |
| } |
| |
| public void visit(CustomTag n) throws JasperException { |
| doVisit(n); |
| visitBody(n); |
| } |
| |
| public void visit(UninterpretedTag n) throws JasperException { |
| doVisit(n); |
| visitBody(n); |
| } |
| |
| public void visit(JspElement n) throws JasperException { |
| doVisit(n); |
| visitBody(n); |
| } |
| |
| public void visit(JspText n) throws JasperException { |
| doVisit(n); |
| visitBody(n); |
| } |
| |
| public void visit(NamedAttribute n) throws JasperException { |
| doVisit(n); |
| visitBody(n); |
| } |
| |
| public void visit(JspBody n) throws JasperException { |
| doVisit(n); |
| visitBody(n); |
| } |
| |
| public void visit(InvokeAction n) throws JasperException { |
| doVisit(n); |
| visitBody(n); |
| } |
| |
| public void visit(DoBodyAction n) throws JasperException { |
| doVisit(n); |
| visitBody(n); |
| } |
| |
| public void visit(TemplateText n) throws JasperException { |
| doVisit(n); |
| } |
| |
| public void visit(JspOutput n) throws JasperException { |
| doVisit(n); |
| } |
| |
| public void visit(AttributeGenerator n) throws JasperException { |
| doVisit(n); |
| } |
| } |
| } |