Impressum Node.java
Interaktion und PortierbarkeitJAVA
/* * 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.jasper.compiler;
/** * An internal data representation of a JSP page or a JSP document (XML). Also * included here is a visitor class for traversing nodes. * * @author Kin-man Chung * @author Jan Luehe * @author Shawn Bayern * @author Mark Roth
*/
// 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;
protectedint beginJavaLine;
protectedint 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;
/** * Zero-arg Constructor.
*/
Node() {
}
/** * Constructor. * * @param start * The location of the jsp page * @param parent * The enclosing node
*/
Node(Mark start, Node parent) { this.startMark = start;
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
*/
Node(String qName, String localName, Attributes attrs, Mark start,
Node parent) { this.qName = qName; this.localName = localName; this.attrs = attrs; this.startMark = start;
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
*/
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;
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
*/
Node(String qName, String localName, String text, Mark start,
Node parent) { this.qName = qName; this.localName = localName; this.text = text; this.startMark = start;
addToParent(parent);
}
public String getQName() { returnthis.qName;
}
public String getLocalName() { returnthis.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() { returnthis.attrs;
}
/* * Gets this Node's xmlns attributes that represent tag libraries (only * meaningful for Nodes parsed from XML syntax)
*/ public Attributes getTaglibAttributes() { returnthis.taglibAttrs;
}
/* * Gets this Node's xmlns attributes that do not represent tag libraries * (only meaningful for Nodes parsed from XML syntax)
*/ public Attributes getNonTaglibXmlnsAttributes() { returnthis.nonTaglibXmlnsAttrs;
}
/** * Get the attribute that is non request time expression, either from the * attribute of the node, or from a jsp:attribute * * @param name The name of the attribute * * @return The attribute value
*/ public String getTextAttribute(String name) {
/** * Searches all sub-nodes of this node for jsp:attribute standard actions * with the given name. * <p> * This should always be called and only be called for nodes that accept * dynamic runtime attribute expressions. * * @param name The name of the attribute * @return the NamedAttribute node of the matching named attribute, nor null * if no such node is found.
*/ 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);
} elseif (!(n instanceof Comment)) { // Nothing can come before jsp:attribute, and only // jsp:body can come after it. break;
}
}
}
/** * 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
*/ abstractvoid accept(Visitor v) throws JasperException;
/* * Adds this Node to the body of the given parent.
*/ privatevoid 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);
}
}
/** * Represents the root of a Jsp page or Jsp document
*/ publicstaticclass Root extends Node {
privatefinal Root parentRoot;
privatefinalboolean isXmlSyntax;
privatefinal String variablePrefix;
// 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.
*/ privateboolean 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.
*/ privateboolean isEncodingSpecifiedInProlog;
/* * Indicates whether an encoding has been explicitly specified in the * page's dom.
*/ privateboolean isBomPresent;
/* * Sequence number for temporary variables.
*/ privateint tempSequenceNumber = 0;
// Figure out and set the parent root
Node r = parent; while ((r != null) && !(r instanceof Node.Root)) {
r = r.getParent();
}
parentRoot = (Node.Root) r;
}
/* * Sets the encoding specified in the JSP config element whose URL * pattern matches the page containing this Root.
*/ publicvoid 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;
}
/** * Generates a new temporary variable name. * * @return The name to use for the temporary variable
*/ public String nextTemporaryVariableName() { if (parentRoot == null) { return variablePrefix + (tempSequenceNumber++);
} else { return parentRoot.nextTemporaryVariableName();
}
}
}
/** * Represents the root of a Jsp document (XML syntax)
*/ publicstaticclass JspRoot extends Node {
/** * 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.
*/ publicvoid addImport(String value) { int start = 0; int index; while ((index = value.indexOf(',', start)) != -1) {
imports.add(validateImport(value.substring(start, index)));
start = index + 1;
} if (start == 0) { // No comma found
imports.add(validateImport(value));
} else {
imports.add(validateImport(value.substring(start)));
}
}
public List<String> getImports() { return imports;
}
/** * Just need enough validation to make sure nothing strange is going on. * The compiler will validate this thoroughly when it tries to compile * the resulting .java file.
*/ private String validateImport(String importEntry) { // This should either be a fully-qualified class name or a package // name with a wildcard if (importEntry.indexOf(';') > -1) { thrownew IllegalArgumentException(
Localizer.getMessage("jsp.error.page.invalid.import"));
} return importEntry.trim();
}
}
/** * Represents an include directive
*/ publicstaticclass IncludeDirective extends Node {
/** * 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.
*/ publicvoid 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<String> getImports() { return imports;
}
}
/** * 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
*/
@Override public String getText() {
String ret = text; if (ret == null) { if (body != null) {
StringBuilder buf = new StringBuilder(); for (int i = 0; i < body.size(); i++) {
buf.append(body.getNode(i).getText());
}
ret = buf.toString();
} else { // Nulls cause NPEs further down the line
ret = "";
}
} return ret;
}
/** * For the same reason as above, the source line information in the * contained TemplateText node should be used.
*/
@Override public Mark getStart() { if (text == null && body != null && body.size() > 0) { return body.getNode(0).getStart();
} else { returnsuper.getStart();
}
}
}
/** * Represents an expression. Expressions in attributes are embedded in the * attribute string and not here.
*/ publicstaticclass Expression extends ScriptingElement {
/** * Represents an EL expression. Expressions in attributes are embedded in * the attribute string and not here.
*/ publicstaticclass ELExpression extends Node {
/** * Collected information about child elements. Used by nodes like CustomTag, * JspBody, and NamedAttribute. The information is set in the Collector.
*/ publicstaticclass ChildInfo { privateboolean scriptless; // true if the tag and its body
// contain no scripting elements. privateboolean hasUseBean;
public ChildInfo getChildInfo() { return childInfo;
}
}
/** * Represents a custom tag
*/ publicstaticclass CustomTag extends ChildInfoBase {
privatefinal String uri;
privatefinal String prefix;
private JspAttribute[] jspAttrs;
private TagData tagData;
private String tagHandlerPoolName;
privatefinal TagInfo tagInfo;
privatefinal TagFileInfo tagFileInfo;
privateClass<?> tagHandlerClass;
private VariableInfo[] varInfos;
privatefinalint customNestingLevel;
privatefinalboolean implementsIterationTag;
privatefinalboolean implementsBodyTag;
privatefinalboolean implementsTryCatchFinally;
privatefinalboolean implementsJspIdConsumer;
privatefinalboolean implementsSimpleTag;
privatefinalboolean implementsDynamicAttributes;
private List<Object> atBeginScriptingVars;
private List<Object> atEndScriptingVars;
private List<Object> nestedScriptingVars;
private Node.CustomTag customTagParent;
private Integer numCount;
privateboolean 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;
public Integer getNumCount() { returnthis.numCount;
}
publicvoid setScriptingVars(List<Object> 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; default: thrownew IllegalArgumentException(
Localizer.getMessage("jsp.error.page.invalid.varscope", Integer.valueOf(scope)));
}
}
/* * Gets the scripting variables for the given scope that need to be * declared.
*/ public List<Object> getScriptingVars(int scope) {
List<Object> 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; default: thrownew IllegalArgumentException(
Localizer.getMessage("jsp.error.page.invalid.varscope", Integer.valueOf(scope)));
}
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.
*/ publicint getCustomNestingLevel() { return customNestingLevel;
}
/** * Checks to see if the attribute of the given name is of type * JspFragment. * * @param name The attribute to check * * @return {@code true} if it is a JspFragment
*/ publicboolean checkIfAttributeIsJspFragment(String name) { boolean result = false;
TagAttributeInfo[] attributes = tagInfo.getAttributes(); for (TagAttributeInfo attribute : attributes) { if (attribute.getName().equals(name)
&& attribute.isFragment()) {
result = true; break;
}
}
/* * 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
*/ privateint 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;
}
/** * 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. * * @return {@code true} if this custom action has an empty body, and * {@code false} otherwise.
*/ publicboolean 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).
*/ publicstaticclass AttributeGenerator extends Node { private String name; // name of the attribute
private CustomTag tag; // The tag this attribute belongs to
/** * @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 = getRoot().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.
*/
@Override public String getText() {
class AttributeVisitor extends Visitor { private String attrValue = null;
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();
}
/** * Trim all whitespace from the left of the template text
*/ publicvoid ltrim() { int index = 0; while ((index < text.length()) && (text.charAt(index) <= ' ')) {
index++;
}
text = text.substring(index);
}
/** * Trim all whitespace from the right of the template text
*/ publicvoid rtrim() { int index = text.length(); while ((index > 0) && (text.charAt(index - 1) <= ' ')) {
index--;
}
text = text.substring(0, index);
}
/** * @return true if this template text contains whitespace only.
*/ publicboolean 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 position 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.
*/ publicvoid addSmap(int srcLine) { if (extraSmap == null) {
extraSmap = new ArrayList<>();
}
extraSmap.add(Integer.valueOf(srcLine));
}
public ArrayList<Integer> getExtraSmap() { return extraSmap;
}
}
/** * 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).
*/
publicstaticclass JspAttribute {
privatefinal String qName;
privatefinal String uri;
privatefinal String localName;
privatefinal String value;
privatefinalboolean expression;
privatefinalboolean dynamic;
privatefinal ELNode.Nodes el;
privatefinal TagAttributeInfo tai;
// If true, this JspAttribute represents a <jsp:attribute> privatefinalboolean namedAttribute;
// The node in the parse tree for the NamedAttribute privatefinal NamedAttribute namedAttributeNode;
/** * Allow node to validate itself. * * @param ef The expression factory to use to evaluate any EL * @param ctx The context to use to evaluate any EL * * @throws ELException If validation fails
*/ publicvoid validateEL(ExpressionFactory ef, ELContext ctx) throws ELException { if (this.el != null) { // determine exact type
ef.createValueExpression(ctx, this.value, String.class);
}
}
/** * 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, TagAttributeInfo tai, 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; this.tai = tai; this.uri = null;
}
/** * @return The name of the attribute
*/ public String getName() { return qName;
}
/** * @return The local name of the attribute
*/ public String getLocalName() { return localName;
}
/**
--> --------------------
--> maximum size reached
--> --------------------
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.49Bemerkung:
Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.