/* | |
* Licensed to the Apache Software Foundation (ASF) under one or more | |
* contributor license agreements. See the NOTICE file distributed with | |
* this work for additional information regarding copyright ownership. | |
* The ASF licenses this file to You 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.struts2.jasper.compiler; | |
import org.apache.struts2.jasper.JasperException; | |
import org.apache.struts2.jasper.compiler.tagplugin.TagPluginContext; | |
import org.xml.sax.Attributes; | |
import javax.servlet.jsp.tagext.*; | |
import java.util.ArrayList; | |
import java.util.Iterator; | |
import java.util.List; | |
import java.util.Vector; | |
/** | |
* 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); | |
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() { | |
if (temporaryVariableName == null) { | |
temporaryVariableName = JspUtil.nextTemporaryVariableName(); | |
} | |
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); | |
} | |
} | |
} |