You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by mu...@apache.org on 2009/09/28 02:43:39 UTC
svn commit: r819435 [5/23] - in
/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper:
./ compiler/ compiler/tagplugin/ el/ runtime/ security/ servlet/
tagplugins/ tagplugins/jstl/ tagplugins/jstl/core/ util/ xmlparser/
Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/Generator.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/Generator.java?rev=819435&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/Generator.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/Generator.java Mon Sep 28 00:43:34 2009
@@ -0,0 +1,4199 @@
+/*
+ * 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;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+import javax.el.MethodExpression;
+import javax.el.ValueExpression;
+import javax.servlet.jsp.tagext.TagAttributeInfo;
+import javax.servlet.jsp.tagext.TagInfo;
+import javax.servlet.jsp.tagext.TagVariableInfo;
+import javax.servlet.jsp.tagext.VariableInfo;
+
+import org.apache.jasper.Constants;
+import org.apache.jasper.JasperException;
+import org.apache.jasper.JspCompilationContext;
+import org.apache.jasper.compiler.Node.NamedAttribute;
+import org.apache.jasper.runtime.JspRuntimeLibrary;
+import org.xml.sax.Attributes;
+
+/**
+ * Generate Java source from Nodes
+ *
+ * @author Anil K. Vijendran
+ * @author Danno Ferrin
+ * @author Mandar Raje
+ * @author Rajiv Mordani
+ * @author Pierre Delisle
+ *
+ * Tomcat 4.1.x and Tomcat 5:
+ * @author Kin-man Chung
+ * @author Jan Luehe
+ * @author Shawn Bayern
+ * @author Mark Roth
+ * @author Denis Benoit
+ *
+ * Tomcat 6.x
+ * @author Jacob Hookom
+ * @author Remy Maucherat
+ */
+
+class Generator {
+
+ private static final Class[] OBJECT_CLASS = { Object.class };
+
+ private static final String VAR_EXPRESSIONFACTORY =
+ System.getProperty("org.apache.jasper.compiler.Generator.VAR_EXPRESSIONFACTORY", "_el_expressionfactory");
+ private static final String VAR_ANNOTATIONPROCESSOR =
+ System.getProperty("org.apache.jasper.compiler.Generator.VAR_ANNOTATIONPROCESSOR", "_jsp_annotationprocessor");
+
+ private ServletWriter out;
+
+ private ArrayList methodsBuffered;
+
+ private FragmentHelperClass fragmentHelperClass;
+
+ private ErrorDispatcher err;
+
+ private BeanRepository beanInfo;
+
+ private JspCompilationContext ctxt;
+
+ private boolean isPoolingEnabled;
+
+ private boolean breakAtLF;
+
+ private String jspIdPrefix;
+
+ private int jspId;
+
+ private PageInfo pageInfo;
+
+ private Vector<String> tagHandlerPoolNames;
+
+ private GenBuffer charArrayBuffer;
+
+ /**
+ * @param s
+ * the input string
+ * @return quoted and escaped string, per Java rule
+ */
+ static String quote(String s) {
+
+ if (s == null)
+ return "null";
+
+ return '"' + escape(s) + '"';
+ }
+
+ /**
+ * @param s
+ * the input string
+ * @return escaped string, per Java rule
+ */
+ static String escape(String s) {
+
+ if (s == null)
+ return "";
+
+ StringBuffer b = new StringBuffer();
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if (c == '"')
+ b.append('\\').append('"');
+ else if (c == '\\')
+ b.append('\\').append('\\');
+ else if (c == '\n')
+ b.append('\\').append('n');
+ else if (c == '\r')
+ b.append('\\').append('r');
+ else
+ b.append(c);
+ }
+ return b.toString();
+ }
+
+ /**
+ * Single quote and escape a character
+ */
+ static String quote(char c) {
+
+ StringBuffer b = new StringBuffer();
+ b.append('\'');
+ if (c == '\'')
+ b.append('\\').append('\'');
+ else if (c == '\\')
+ b.append('\\').append('\\');
+ else if (c == '\n')
+ b.append('\\').append('n');
+ else if (c == '\r')
+ b.append('\\').append('r');
+ else
+ b.append(c);
+ b.append('\'');
+ return b.toString();
+ }
+
+ private String createJspId() throws JasperException {
+ if (this.jspIdPrefix == null) {
+ StringBuffer sb = new StringBuffer(32);
+ String name = ctxt.getServletJavaFileName();
+ sb.append("jsp_").append(Math.abs(name.hashCode())).append('_');
+ this.jspIdPrefix = sb.toString();
+ }
+ return this.jspIdPrefix + (this.jspId++);
+ }
+
+ /**
+ * Generates declarations. This includes "info" of the page directive, and
+ * scriptlet declarations.
+ */
+ private void generateDeclarations(Node.Nodes page) throws JasperException {
+
+ class DeclarationVisitor extends Node.Visitor {
+
+ private boolean getServletInfoGenerated = false;
+
+ /*
+ * Generates getServletInfo() method that returns the value of the
+ * page directive's 'info' attribute, if present.
+ *
+ * The Validator has already ensured that if the translation unit
+ * contains more than one page directive with an 'info' attribute,
+ * their values match.
+ */
+ public void visit(Node.PageDirective n) throws JasperException {
+
+ if (getServletInfoGenerated) {
+ return;
+ }
+
+ String info = n.getAttributeValue("info");
+ if (info == null)
+ return;
+
+ getServletInfoGenerated = true;
+ out.printil("public String getServletInfo() {");
+ out.pushIndent();
+ out.printin("return ");
+ out.print(quote(info));
+ out.println(";");
+ out.popIndent();
+ out.printil("}");
+ out.println();
+ }
+
+ public void visit(Node.Declaration n) throws JasperException {
+ n.setBeginJavaLine(out.getJavaLine());
+ out.printMultiLn(new String(n.getText()));
+ out.println();
+ n.setEndJavaLine(out.getJavaLine());
+ }
+
+ // Custom Tags may contain declarations from tag plugins.
+ public void visit(Node.CustomTag n) throws JasperException {
+ if (n.useTagPlugin()) {
+ if (n.getAtSTag() != null) {
+ n.getAtSTag().visit(this);
+ }
+ visitBody(n);
+ if (n.getAtETag() != null) {
+ n.getAtETag().visit(this);
+ }
+ } else {
+ visitBody(n);
+ }
+ }
+ }
+
+ out.println();
+ page.visit(new DeclarationVisitor());
+ }
+
+ /**
+ * Compiles list of tag handler pool names.
+ */
+ private void compileTagHandlerPoolList(Node.Nodes page)
+ throws JasperException {
+
+ class TagHandlerPoolVisitor extends Node.Visitor {
+
+ private Vector names;
+
+ /*
+ * Constructor
+ *
+ * @param v Vector of tag handler pool names to populate
+ */
+ TagHandlerPoolVisitor(Vector v) {
+ names = v;
+ }
+
+ /*
+ * Gets the name of the tag handler pool for the given custom tag
+ * and adds it to the list of tag handler pool names unless it is
+ * already contained in it.
+ */
+ public void visit(Node.CustomTag n) throws JasperException {
+
+ if (!n.implementsSimpleTag()) {
+ String name = createTagHandlerPoolName(n.getPrefix(), n
+ .getLocalName(), n.getAttributes(),
+ n.getNamedAttributeNodes(), n.hasEmptyBody());
+ n.setTagHandlerPoolName(name);
+ if (!names.contains(name)) {
+ names.add(name);
+ }
+ }
+ visitBody(n);
+ }
+
+ /*
+ * Creates the name of the tag handler pool whose tag handlers may
+ * be (re)used to service this action.
+ *
+ * @return The name of the tag handler pool
+ */
+ private String createTagHandlerPoolName(String prefix,
+ String shortName, Attributes attrs, Node.Nodes namedAttrs,
+ boolean hasEmptyBody) {
+ String poolName = null;
+
+ poolName = "_jspx_tagPool_" + prefix + "_" + shortName;
+ if (attrs != null) {
+ String[] attrNames =
+ new String[attrs.getLength() + namedAttrs.size()];
+ for (int i = 0; i < attrNames.length; i++) {
+ attrNames[i] = attrs.getQName(i);
+ }
+ for (int i = 0; i < namedAttrs.size(); i++) {
+ attrNames[attrs.getLength() + i] =
+ ((NamedAttribute) namedAttrs.getNode(i)).getQName();
+ }
+ Arrays.sort(attrNames, Collections.reverseOrder());
+ if (attrNames.length > 0) {
+ poolName = poolName + "&";
+ }
+ for (int i = 0; i < attrNames.length; i++) {
+ poolName = poolName + "_" + attrNames[i];
+ }
+ }
+ if (hasEmptyBody) {
+ poolName = poolName + "_nobody";
+ }
+ return JspUtil.makeJavaIdentifier(poolName);
+ }
+ }
+
+ page.visit(new TagHandlerPoolVisitor(tagHandlerPoolNames));
+ }
+
+ private void declareTemporaryScriptingVars(Node.Nodes page)
+ throws JasperException {
+
+ class ScriptingVarVisitor extends Node.Visitor {
+
+ private Vector vars;
+
+ ScriptingVarVisitor() {
+ vars = new Vector();
+ }
+
+ public void visit(Node.CustomTag n) throws JasperException {
+
+ if (n.getCustomNestingLevel() > 0) {
+ TagVariableInfo[] tagVarInfos = n.getTagVariableInfos();
+ VariableInfo[] varInfos = n.getVariableInfos();
+
+ if (varInfos.length > 0) {
+ for (int i = 0; i < varInfos.length; i++) {
+ String varName = varInfos[i].getVarName();
+ String tmpVarName = "_jspx_" + varName + "_"
+ + n.getCustomNestingLevel();
+ if (!vars.contains(tmpVarName)) {
+ vars.add(tmpVarName);
+ out.printin(varInfos[i].getClassName());
+ out.print(" ");
+ out.print(tmpVarName);
+ out.print(" = ");
+ out.print(null);
+ out.println(";");
+ }
+ }
+ } else {
+ for (int i = 0; i < tagVarInfos.length; i++) {
+ String varName = tagVarInfos[i].getNameGiven();
+ if (varName == null) {
+ varName = n.getTagData().getAttributeString(
+ tagVarInfos[i].getNameFromAttribute());
+ } else if (tagVarInfos[i].getNameFromAttribute() != null) {
+ // alias
+ continue;
+ }
+ String tmpVarName = "_jspx_" + varName + "_"
+ + n.getCustomNestingLevel();
+ if (!vars.contains(tmpVarName)) {
+ vars.add(tmpVarName);
+ out.printin(tagVarInfos[i].getClassName());
+ out.print(" ");
+ out.print(tmpVarName);
+ out.print(" = ");
+ out.print(null);
+ out.println(";");
+ }
+ }
+ }
+ }
+
+ visitBody(n);
+ }
+ }
+
+ page.visit(new ScriptingVarVisitor());
+ }
+
+ /**
+ * Generates the _jspInit() method for instantiating the tag handler pools.
+ * For tag file, _jspInit has to be invoked manually, and the ServletConfig
+ * object explicitly passed.
+ *
+ * In JSP 2.1, we also instantiate an ExpressionFactory
+ */
+ private void generateInit() {
+
+ if (ctxt.isTagFile()) {
+ out.printil("private void _jspInit(ServletConfig config) {");
+ } else {
+ out.printil("public void _jspInit() {");
+ }
+
+ out.pushIndent();
+ if (isPoolingEnabled) {
+ for (int i = 0; i < tagHandlerPoolNames.size(); i++) {
+ out.printin(tagHandlerPoolNames.elementAt(i));
+ out.print(" = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(");
+ if (ctxt.isTagFile()) {
+ out.print("config");
+ } else {
+ out.print("getServletConfig()");
+ }
+ out.println(");");
+ }
+ }
+
+ out.printin(VAR_EXPRESSIONFACTORY);
+ out.print(" = _jspxFactory.getJspApplicationContext(");
+ if (ctxt.isTagFile()) {
+ out.print("config");
+ } else {
+ out.print("getServletConfig()");
+ }
+ out.println(".getServletContext()).getExpressionFactory();");
+
+ out.printin(VAR_ANNOTATIONPROCESSOR);
+ out.print(" = (org.apache.AnnotationProcessor) ");
+ if (ctxt.isTagFile()) {
+ out.print("config");
+ } else {
+ out.print("getServletConfig()");
+ }
+ out.println(".getServletContext().getAttribute(org.apache.AnnotationProcessor.class.getName());");
+
+ out.popIndent();
+ out.printil("}");
+ out.println();
+ }
+
+ /**
+ * Generates the _jspDestroy() method which is responsible for calling the
+ * release() method on every tag handler in any of the tag handler pools.
+ */
+ private void generateDestroy() {
+
+ out.printil("public void _jspDestroy() {");
+ out.pushIndent();
+
+ if (isPoolingEnabled) {
+ for (int i = 0; i < tagHandlerPoolNames.size(); i++) {
+ out.printin((String) tagHandlerPoolNames.elementAt(i));
+ out.println(".release();");
+ }
+ }
+
+ out.popIndent();
+ out.printil("}");
+ out.println();
+ }
+
+ /**
+ * Generate preamble package name (shared by servlet and tag handler
+ * preamble generation)
+ */
+ private void genPreamblePackage(String packageName) throws JasperException {
+ if (!"".equals(packageName) && packageName != null) {
+ out.printil("package " + packageName + ";");
+ out.println();
+ }
+ }
+
+ /**
+ * Generate preamble imports (shared by servlet and tag handler preamble
+ * generation)
+ */
+ private void genPreambleImports() throws JasperException {
+ Iterator iter = pageInfo.getImports().iterator();
+ while (iter.hasNext()) {
+ out.printin("import ");
+ out.print((String) iter.next());
+ out.println(";");
+ }
+
+ out.println();
+ }
+
+ /**
+ * Generation of static initializers in preamble. For example, dependant
+ * list, el function map, prefix map. (shared by servlet and tag handler
+ * preamble generation)
+ */
+ private void genPreambleStaticInitializers() throws JasperException {
+ out.printil("private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();");
+ out.println();
+
+ // Static data for getDependants()
+ out.printil("private static java.util.List _jspx_dependants;");
+ out.println();
+ List dependants = pageInfo.getDependants();
+ Iterator iter = dependants.iterator();
+ if (!dependants.isEmpty()) {
+ out.printil("static {");
+ out.pushIndent();
+ out.printin("_jspx_dependants = new java.util.ArrayList(");
+ out.print("" + dependants.size());
+ out.println(");");
+ while (iter.hasNext()) {
+ out.printin("_jspx_dependants.add(\"");
+ out.print((String) iter.next());
+ out.println("\");");
+ }
+ out.popIndent();
+ out.printil("}");
+ out.println();
+ }
+ }
+
+ /**
+ * Declare tag handler pools (tags of the same type and with the same
+ * attribute set share the same tag handler pool) (shared by servlet and tag
+ * handler preamble generation)
+ *
+ * In JSP 2.1, we also scope an instance of ExpressionFactory
+ */
+ private void genPreambleClassVariableDeclarations(String className)
+ throws JasperException {
+ if (isPoolingEnabled && !tagHandlerPoolNames.isEmpty()) {
+ for (int i = 0; i < tagHandlerPoolNames.size(); i++) {
+ out.printil("private org.apache.jasper.runtime.TagHandlerPool "
+ + tagHandlerPoolNames.elementAt(i) + ";");
+ }
+ out.println();
+ }
+ out.printin("private javax.el.ExpressionFactory ");
+ out.print(VAR_EXPRESSIONFACTORY);
+ out.println(";");
+ out.printin("private org.apache.AnnotationProcessor ");
+ out.print(VAR_ANNOTATIONPROCESSOR);
+ out.println(";");
+ out.println();
+ }
+
+ /**
+ * Declare general-purpose methods (shared by servlet and tag handler
+ * preamble generation)
+ */
+ private void genPreambleMethods() throws JasperException {
+ // Method used to get compile time file dependencies
+ out.printil("public Object getDependants() {");
+ out.pushIndent();
+ out.printil("return _jspx_dependants;");
+ out.popIndent();
+ out.printil("}");
+ out.println();
+
+ generateInit();
+ generateDestroy();
+ }
+
+ /**
+ * Generates the beginning of the static portion of the servlet.
+ */
+ private void generatePreamble(Node.Nodes page) throws JasperException {
+
+ String servletPackageName = ctxt.getServletPackageName();
+ String servletClassName = ctxt.getServletClassName();
+ String serviceMethodName = Constants.SERVICE_METHOD_NAME;
+
+ // First the package name:
+ genPreamblePackage(servletPackageName);
+
+ // Generate imports
+ genPreambleImports();
+
+ // Generate class declaration
+ out.printin("public final class ");
+ out.print(servletClassName);
+ out.print(" extends ");
+ out.println(pageInfo.getExtends());
+ out.printin(" implements org.apache.jasper.runtime.JspSourceDependent");
+ if (!pageInfo.isThreadSafe()) {
+ out.println(",");
+ out.printin(" SingleThreadModel");
+ }
+ out.println(" {");
+ out.pushIndent();
+
+ // Class body begins here
+ generateDeclarations(page);
+
+ // Static initializations here
+ genPreambleStaticInitializers();
+
+ // Class variable declarations
+ genPreambleClassVariableDeclarations(servletClassName);
+
+ // Constructor
+ // generateConstructor(className);
+
+ // Methods here
+ genPreambleMethods();
+
+ // Now the service method
+ out.printin("public void ");
+ out.print(serviceMethodName);
+ out.println("(HttpServletRequest request, HttpServletResponse response)");
+ out.println(" throws java.io.IOException, ServletException {");
+
+ out.pushIndent();
+ out.println();
+
+ // Local variable declarations
+ out.printil("PageContext pageContext = null;");
+
+ if (pageInfo.isSession())
+ out.printil("HttpSession session = null;");
+
+ if (pageInfo.isErrorPage()) {
+ out.printil("Throwable exception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request);");
+ out.printil("if (exception != null) {");
+ out.pushIndent();
+ out.printil("response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);");
+ out.popIndent();
+ out.printil("}");
+ }
+
+ out.printil("ServletContext application = null;");
+ out.printil("ServletConfig config = null;");
+ out.printil("JspWriter out = null;");
+ out.printil("Object page = this;");
+
+ out.printil("JspWriter _jspx_out = null;");
+ out.printil("PageContext _jspx_page_context = null;");
+ out.println();
+
+ declareTemporaryScriptingVars(page);
+ out.println();
+
+ out.printil("try {");
+ out.pushIndent();
+
+ out.printin("response.setContentType(");
+ out.print(quote(pageInfo.getContentType()));
+ out.println(");");
+
+ if (ctxt.getOptions().isXpoweredBy()) {
+ out.printil("response.addHeader(\"X-Powered-By\", \"JSP/2.1\");");
+ }
+
+ out
+ .printil("pageContext = _jspxFactory.getPageContext(this, request, response,");
+ out.printin("\t\t\t");
+ out.print(quote(pageInfo.getErrorPage()));
+ out.print(", " + pageInfo.isSession());
+ out.print(", " + pageInfo.getBuffer());
+ out.print(", " + pageInfo.isAutoFlush());
+ out.println(");");
+ out.printil("_jspx_page_context = pageContext;");
+
+ out.printil("application = pageContext.getServletContext();");
+ out.printil("config = pageContext.getServletConfig();");
+
+ if (pageInfo.isSession())
+ out.printil("session = pageContext.getSession();");
+ out.printil("out = pageContext.getOut();");
+ out.printil("_jspx_out = out;");
+ out.println();
+ }
+
+ /**
+ * Generates an XML Prolog, which includes an XML declaration and an XML
+ * doctype declaration.
+ */
+ private void generateXmlProlog(Node.Nodes page) {
+
+ /*
+ * An XML declaration is generated under the following conditions: -
+ * 'omit-xml-declaration' attribute of <jsp:output> action is set to
+ * "no" or "false" - JSP document without a <jsp:root>
+ */
+ String omitXmlDecl = pageInfo.getOmitXmlDecl();
+ if ((omitXmlDecl != null && !JspUtil.booleanValue(omitXmlDecl))
+ || (omitXmlDecl == null && page.getRoot().isXmlSyntax()
+ && !pageInfo.hasJspRoot() && !ctxt.isTagFile())) {
+ String cType = pageInfo.getContentType();
+ String charSet = cType.substring(cType.indexOf("charset=") + 8);
+ out.printil("out.write(\"<?xml version=\\\"1.0\\\" encoding=\\\""
+ + charSet + "\\\"?>\\n\");");
+ }
+
+ /*
+ * Output a DOCTYPE declaration if the doctype-root-element appears. If
+ * doctype-public appears: <!DOCTYPE name PUBLIC "doctypePublic"
+ * "doctypeSystem"> else <!DOCTYPE name SYSTEM "doctypeSystem" >
+ */
+
+ String doctypeName = pageInfo.getDoctypeName();
+ if (doctypeName != null) {
+ String doctypePublic = pageInfo.getDoctypePublic();
+ String doctypeSystem = pageInfo.getDoctypeSystem();
+ out.printin("out.write(\"<!DOCTYPE ");
+ out.print(doctypeName);
+ if (doctypePublic == null) {
+ out.print(" SYSTEM \\\"");
+ } else {
+ out.print(" PUBLIC \\\"");
+ out.print(doctypePublic);
+ out.print("\\\" \\\"");
+ }
+ out.print(doctypeSystem);
+ out.println("\\\">\\n\");");
+ }
+ }
+
+ /*
+ * Generates the constructor. (shared by servlet and tag handler preamble
+ * generation)
+ */
+ private void generateConstructor(String className) {
+ out.printil("public " + className + "() {");
+ out.printil("}");
+ out.println();
+ }
+
+ /**
+ * A visitor that generates codes for the elements in the page.
+ */
+ class GenerateVisitor extends Node.Visitor {
+
+ /*
+ * Hashtable containing introspection information on tag handlers:
+ * <key>: tag prefix <value>: hashtable containing introspection on tag
+ * handlers: <key>: tag short name <value>: introspection info of tag
+ * handler for <prefix:shortName> tag
+ */
+ private Hashtable handlerInfos;
+
+ private Hashtable tagVarNumbers;
+
+ private String parent;
+
+ private boolean isSimpleTagParent; // Is parent a SimpleTag?
+
+ private String pushBodyCountVar;
+
+ private String simpleTagHandlerVar;
+
+ private boolean isSimpleTagHandler;
+
+ private boolean isFragment;
+
+ private boolean isTagFile;
+
+ private ServletWriter out;
+
+ private ArrayList methodsBuffered;
+
+ private FragmentHelperClass fragmentHelperClass;
+
+ private int methodNesting;
+
+ private TagInfo tagInfo;
+
+ private ClassLoader loader;
+
+ private int charArrayCount;
+
+ private HashMap textMap;
+
+ /**
+ * Constructor.
+ */
+ public GenerateVisitor(boolean isTagFile, ServletWriter out,
+ ArrayList methodsBuffered,
+ FragmentHelperClass fragmentHelperClass, ClassLoader loader,
+ TagInfo tagInfo) {
+
+ this.isTagFile = isTagFile;
+ this.out = out;
+ this.methodsBuffered = methodsBuffered;
+ this.fragmentHelperClass = fragmentHelperClass;
+ this.loader = loader;
+ this.tagInfo = tagInfo;
+ methodNesting = 0;
+ handlerInfos = new Hashtable();
+ tagVarNumbers = new Hashtable();
+ textMap = new HashMap();
+ }
+
+ /**
+ * Returns an attribute value, optionally URL encoded. If the value is a
+ * runtime expression, the result is the expression itself, as a string.
+ * If the result is an EL expression, we insert a call to the
+ * interpreter. If the result is a Named Attribute we insert the
+ * generated variable name. Otherwise the result is a string literal,
+ * quoted and escaped.
+ *
+ * @param attr
+ * An JspAttribute object
+ * @param encode
+ * true if to be URL encoded
+ * @param expectedType
+ * the expected type for an EL evaluation (ignored for
+ * attributes that aren't EL expressions)
+ */
+ private String attributeValue(Node.JspAttribute attr, boolean encode,
+ Class expectedType) {
+ String v = attr.getValue();
+ if (!attr.isNamedAttribute() && (v == null))
+ return "";
+
+ if (attr.isExpression()) {
+ if (encode) {
+ return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode(String.valueOf("
+ + v + "), request.getCharacterEncoding())";
+ }
+ return v;
+ } else if (attr.isELInterpreterInput()) {
+ v = attributeValueWithEL(this.isTagFile, v, expectedType,
+ attr.getEL().getMapName());
+ if (encode) {
+ return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("
+ + v + ", request.getCharacterEncoding())";
+ }
+ return v;
+ } else if (attr.isNamedAttribute()) {
+ return attr.getNamedAttributeNode().getTemporaryVariableName();
+ } else {
+ if (encode) {
+ return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("
+ + quote(v) + ", request.getCharacterEncoding())";
+ }
+ return quote(v);
+ }
+ }
+
+
+ /*
+ * When interpreting the EL attribute value, literals outside the EL
+ * must not be unescaped but the EL processor will unescape them.
+ * Therefore, make sure only the EL expressions are processed by the EL
+ * processor.
+ */
+ private String attributeValueWithEL(boolean isTag, String tx,
+ Class<?> expectedType, String mapName) {
+ if (tx==null) return null;
+ Class<?> type = expectedType;
+ int size = tx.length();
+ StringBuffer output = new StringBuffer(size);
+ boolean el = false;
+ int i = 0;
+ int mark = 0;
+ char ch;
+
+ while(i < size){
+ ch = tx.charAt(i);
+
+ // Start of an EL expression
+ if (!el && i+1 < size && ch == '$' && tx.charAt(i+1)=='{') {
+ if (mark < i) {
+ if (output.length() > 0) {
+ output.append(" + ");
+ // Composite expression - must coerce to String
+ type = String.class;
+ }
+ output.append(quote(tx.substring(mark, i)));
+ }
+ mark = i;
+ el = true;
+ i += 2;
+ } else if (ch=='\\' && i+1 < size &&
+ (tx.charAt(i+1)=='$' || tx.charAt(i+1)=='}')) {
+ // Skip an escaped $ or }
+ i += 2;
+ } else if (el && ch=='}') {
+ // End of an EL expression
+ if (output.length() > 0) {
+ output.append(" + ");
+ // Composite expression - must coerce to String
+ type = String.class;
+ }
+ output.append(
+ JspUtil.interpreterCall(isTag,
+ tx.substring(mark, i+1), type,
+ mapName, false));
+ mark = i + 1;
+ el = false;
+ ++i;
+ } else {
+ // Nothing to see here - move to next character
+ ++i;
+ }
+ }
+ if (!el && mark < i) {
+ if (output.length() > 0) {
+ output.append(" + ");
+ }
+ output.append(quote(tx.substring(mark, i)));
+ }
+ return output.toString();
+ }
+
+
+ /**
+ * Prints the attribute value specified in the param action, in the form
+ * of name=value string.
+ *
+ * @param n
+ * the parent node for the param action nodes.
+ */
+ private void printParams(Node n, String pageParam, boolean literal)
+ throws JasperException {
+
+ class ParamVisitor extends Node.Visitor {
+ String separator;
+
+ ParamVisitor(String separator) {
+ this.separator = separator;
+ }
+
+ public void visit(Node.ParamAction n) throws JasperException {
+
+ out.print(" + ");
+ out.print(separator);
+ out.print(" + ");
+ out.print("org.apache.jasper.runtime.JspRuntimeLibrary."
+ + "URLEncode(" + quote(n.getTextAttribute("name"))
+ + ", request.getCharacterEncoding())");
+ out.print("+ \"=\" + ");
+ out.print(attributeValue(n.getValue(), true, String.class));
+
+ // The separator is '&' after the second use
+ separator = "\"&\"";
+ }
+ }
+
+ String sep;
+ if (literal) {
+ sep = pageParam.indexOf('?') > 0 ? "\"&\"" : "\"?\"";
+ } else {
+ sep = "((" + pageParam + ").indexOf('?')>0? '&': '?')";
+ }
+ if (n.getBody() != null) {
+ n.getBody().visit(new ParamVisitor(sep));
+ }
+ }
+
+ public void visit(Node.Expression n) throws JasperException {
+ n.setBeginJavaLine(out.getJavaLine());
+ out.printin("out.print(");
+ out.printMultiLn(n.getText());
+ out.println(");");
+ n.setEndJavaLine(out.getJavaLine());
+ }
+
+ public void visit(Node.Scriptlet n) throws JasperException {
+ n.setBeginJavaLine(out.getJavaLine());
+ out.printMultiLn(n.getText());
+ out.println();
+ n.setEndJavaLine(out.getJavaLine());
+ }
+
+ public void visit(Node.ELExpression n) throws JasperException {
+ n.setBeginJavaLine(out.getJavaLine());
+ if (!pageInfo.isELIgnored() && (n.getEL() != null)) {
+ out.printil("out.write("
+ + JspUtil.interpreterCall(this.isTagFile, n.getType() + "{"
+ + new String(n.getText()) + "}", String.class,
+ n.getEL().getMapName(), false) + ");");
+ } else {
+ out.printil("out.write("
+ + quote(n.getType() + "{" + new String(n.getText()) + "}") + ");");
+ }
+ n.setEndJavaLine(out.getJavaLine());
+ }
+
+ public void visit(Node.IncludeAction n) throws JasperException {
+
+ String flush = n.getTextAttribute("flush");
+ Node.JspAttribute page = n.getPage();
+
+ boolean isFlush = false; // default to false;
+ if ("true".equals(flush))
+ isFlush = true;
+
+ n.setBeginJavaLine(out.getJavaLine());
+
+ String pageParam;
+ if (page.isNamedAttribute()) {
+ // If the page for jsp:include was specified via
+ // jsp:attribute, first generate code to evaluate
+ // that body.
+ pageParam = generateNamedAttributeValue(page
+ .getNamedAttributeNode());
+ } else {
+ pageParam = attributeValue(page, false, String.class);
+ }
+
+ // If any of the params have their values specified by
+ // jsp:attribute, prepare those values first.
+ Node jspBody = findJspBody(n);
+ if (jspBody != null) {
+ prepareParams(jspBody);
+ } else {
+ prepareParams(n);
+ }
+
+ out
+ .printin("org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "
+ + pageParam);
+ printParams(n, pageParam, page.isLiteral());
+ out.println(", out, " + isFlush + ");");
+
+ n.setEndJavaLine(out.getJavaLine());
+ }
+
+ /**
+ * Scans through all child nodes of the given parent for <param>
+ * subelements. For each <param> element, if its value is specified via
+ * a Named Attribute (<jsp:attribute>), generate the code to evaluate
+ * those bodies first.
+ * <p>
+ * If parent is null, simply returns.
+ */
+ private void prepareParams(Node parent) throws JasperException {
+ if (parent == null)
+ return;
+
+ Node.Nodes subelements = parent.getBody();
+ if (subelements != null) {
+ for (int i = 0; i < subelements.size(); i++) {
+ Node n = subelements.getNode(i);
+ if (n instanceof Node.ParamAction) {
+ Node.Nodes paramSubElements = n.getBody();
+ for (int j = 0; (paramSubElements != null)
+ && (j < paramSubElements.size()); j++) {
+ Node m = paramSubElements.getNode(j);
+ if (m instanceof Node.NamedAttribute) {
+ generateNamedAttributeValue((Node.NamedAttribute) m);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Finds the <jsp:body> subelement of the given parent node. If not
+ * found, null is returned.
+ */
+ private Node.JspBody findJspBody(Node parent) throws JasperException {
+ Node.JspBody result = null;
+
+ Node.Nodes subelements = parent.getBody();
+ for (int i = 0; (subelements != null) && (i < subelements.size()); i++) {
+ Node n = subelements.getNode(i);
+ if (n instanceof Node.JspBody) {
+ result = (Node.JspBody) n;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ public void visit(Node.ForwardAction n) throws JasperException {
+ Node.JspAttribute page = n.getPage();
+
+ n.setBeginJavaLine(out.getJavaLine());
+
+ out.printil("if (true) {"); // So that javac won't complain about
+ out.pushIndent(); // codes after "return"
+
+ String pageParam;
+ if (page.isNamedAttribute()) {
+ // If the page for jsp:forward was specified via
+ // jsp:attribute, first generate code to evaluate
+ // that body.
+ pageParam = generateNamedAttributeValue(page
+ .getNamedAttributeNode());
+ } else {
+ pageParam = attributeValue(page, false, String.class);
+ }
+
+ // If any of the params have their values specified by
+ // jsp:attribute, prepare those values first.
+ Node jspBody = findJspBody(n);
+ if (jspBody != null) {
+ prepareParams(jspBody);
+ } else {
+ prepareParams(n);
+ }
+
+ out.printin("_jspx_page_context.forward(");
+ out.print(pageParam);
+ printParams(n, pageParam, page.isLiteral());
+ out.println(");");
+ if (isTagFile || isFragment) {
+ out.printil("throw new SkipPageException();");
+ } else {
+ out.printil((methodNesting > 0) ? "return true;" : "return;");
+ }
+ out.popIndent();
+ out.printil("}");
+
+ n.setEndJavaLine(out.getJavaLine());
+ // XXX Not sure if we can eliminate dead codes after this.
+ }
+
+ public void visit(Node.GetProperty n) throws JasperException {
+ String name = n.getTextAttribute("name");
+ String property = n.getTextAttribute("property");
+
+ n.setBeginJavaLine(out.getJavaLine());
+
+ if (beanInfo.checkVariable(name)) {
+ // Bean is defined using useBean, introspect at compile time
+ Class bean = beanInfo.getBeanType(name);
+ String beanName = JspUtil.getCanonicalName(bean);
+ java.lang.reflect.Method meth = JspRuntimeLibrary
+ .getReadMethod(bean, property);
+ String methodName = meth.getName();
+ out
+ .printil("out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString("
+ + "((("
+ + beanName
+ + ")_jspx_page_context.findAttribute("
+ + "\""
+ + name + "\"))." + methodName + "())));");
+ } else {
+ // The object could be a custom action with an associated
+ // VariableInfo entry for this name.
+ // Get the class name and then introspect at runtime.
+ out
+ .printil("out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString"
+ + "(org.apache.jasper.runtime.JspRuntimeLibrary.handleGetProperty"
+ + "(_jspx_page_context.getAttribute(\""
+ + name
+ + "\", PageContext.PAGE_SCOPE), \""
+ + property
+ + "\")));");
+ }
+
+ n.setEndJavaLine(out.getJavaLine());
+ }
+
+ public void visit(Node.SetProperty n) throws JasperException {
+ String name = n.getTextAttribute("name");
+ String property = n.getTextAttribute("property");
+ String param = n.getTextAttribute("param");
+ Node.JspAttribute value = n.getValue();
+
+ n.setBeginJavaLine(out.getJavaLine());
+
+ if ("*".equals(property)) {
+ out
+ .printil("org.apache.jasper.runtime.JspRuntimeLibrary.introspect("
+ + "_jspx_page_context.findAttribute("
+ + "\""
+ + name + "\"), request);");
+ } else if (value == null) {
+ if (param == null)
+ param = property; // default to same as property
+ out
+ .printil("org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper("
+ + "_jspx_page_context.findAttribute(\""
+ + name
+ + "\"), \""
+ + property
+ + "\", request.getParameter(\""
+ + param
+ + "\"), "
+ + "request, \""
+ + param
+ + "\", false);");
+ } else if (value.isExpression()) {
+ out
+ .printil("org.apache.jasper.runtime.JspRuntimeLibrary.handleSetProperty("
+ + "_jspx_page_context.findAttribute(\""
+ + name
+ + "\"), \"" + property + "\",");
+ out.print(attributeValue(value, false, null));
+ out.println(");");
+ } else if (value.isELInterpreterInput()) {
+ // We've got to resolve the very call to the interpreter
+ // at runtime since we don't know what type to expect
+ // in the general case; we thus can't hard-wire the call
+ // into the generated code. (XXX We could, however,
+ // optimize the case where the bean is exposed with
+ // <jsp:useBean>, much as the code here does for
+ // getProperty.)
+
+ // The following holds true for the arguments passed to
+ // JspRuntimeLibrary.handleSetPropertyExpression():
+ // - 'pageContext' is a VariableResolver.
+ // - 'this' (either the generated Servlet or the generated tag
+ // handler for Tag files) is a FunctionMapper.
+ out
+ .printil("org.apache.jasper.runtime.JspRuntimeLibrary.handleSetPropertyExpression("
+ + "_jspx_page_context.findAttribute(\""
+ + name
+ + "\"), \""
+ + property
+ + "\", "
+ + quote(value.getValue())
+ + ", "
+ + "_jspx_page_context, "
+ + value.getEL().getMapName() + ");");
+ } else if (value.isNamedAttribute()) {
+ // If the value for setProperty was specified via
+ // jsp:attribute, first generate code to evaluate
+ // that body.
+ String valueVarName = generateNamedAttributeValue(value
+ .getNamedAttributeNode());
+ out
+ .printil("org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper("
+ + "_jspx_page_context.findAttribute(\""
+ + name
+ + "\"), \""
+ + property
+ + "\", "
+ + valueVarName
+ + ", null, null, false);");
+ } else {
+ out
+ .printin("org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper("
+ + "_jspx_page_context.findAttribute(\""
+ + name
+ + "\"), \"" + property + "\", ");
+ out.print(attributeValue(value, false, null));
+ out.println(", null, null, false);");
+ }
+
+ n.setEndJavaLine(out.getJavaLine());
+ }
+
+ public void visit(Node.UseBean n) throws JasperException {
+
+ String name = n.getTextAttribute("id");
+ String scope = n.getTextAttribute("scope");
+ String klass = n.getTextAttribute("class");
+ String type = n.getTextAttribute("type");
+ Node.JspAttribute beanName = n.getBeanName();
+
+ // If "class" is specified, try an instantiation at compile time
+ boolean generateNew = false;
+ String canonicalName = null; // Canonical name for klass
+ if (klass != null) {
+ try {
+ Class bean = ctxt.getClassLoader().loadClass(klass);
+ if (klass.indexOf('$') >= 0) {
+ // Obtain the canonical type name
+ canonicalName = JspUtil.getCanonicalName(bean);
+ } else {
+ canonicalName = klass;
+ }
+ int modifiers = bean.getModifiers();
+ if (!Modifier.isPublic(modifiers)
+ || Modifier.isInterface(modifiers)
+ || Modifier.isAbstract(modifiers)) {
+ throw new Exception("Invalid bean class modifier");
+ }
+ // Check that there is a 0 arg constructor
+ bean.getConstructor(new Class[] {});
+ // At compile time, we have determined that the bean class
+ // exists, with a public zero constructor, new() can be
+ // used for bean instantiation.
+ generateNew = true;
+ } catch (Exception e) {
+ // Cannot instantiate the specified class, either a
+ // compilation error or a runtime error will be raised,
+ // depending on a compiler flag.
+ if (ctxt.getOptions()
+ .getErrorOnUseBeanInvalidClassAttribute()) {
+ err.jspError(n, "jsp.error.invalid.bean", klass);
+ }
+ if (canonicalName == null) {
+ // Doing our best here to get a canonical name
+ // from the binary name, should work 99.99% of time.
+ canonicalName = klass.replace('$', '.');
+ }
+ }
+ if (type == null) {
+ // if type is unspecified, use "class" as type of bean
+ type = canonicalName;
+ }
+ }
+
+ String scopename = "PageContext.PAGE_SCOPE"; // Default to page
+ String lock = "_jspx_page_context";
+
+ if ("request".equals(scope)) {
+ scopename = "PageContext.REQUEST_SCOPE";
+ lock = "request";
+ } else if ("session".equals(scope)) {
+ scopename = "PageContext.SESSION_SCOPE";
+ lock = "session";
+ } else if ("application".equals(scope)) {
+ scopename = "PageContext.APPLICATION_SCOPE";
+ lock = "application";
+ }
+
+ n.setBeginJavaLine(out.getJavaLine());
+
+ // Declare bean
+ out.printin(type);
+ out.print(' ');
+ out.print(name);
+ out.println(" = null;");
+
+ // Lock while getting or creating bean
+ out.printin("synchronized (");
+ out.print(lock);
+ out.println(") {");
+ out.pushIndent();
+
+ // Locate bean from context
+ out.printin(name);
+ out.print(" = (");
+ out.print(type);
+ out.print(") _jspx_page_context.getAttribute(");
+ out.print(quote(name));
+ out.print(", ");
+ out.print(scopename);
+ out.println(");");
+
+ // Create bean
+ /*
+ * Check if bean is alredy there
+ */
+ out.printin("if (");
+ out.print(name);
+ out.println(" == null){");
+ out.pushIndent();
+ if (klass == null && beanName == null) {
+ /*
+ * If both class name and beanName is not specified, the bean
+ * must be found locally, otherwise it's an error
+ */
+ out
+ .printin("throw new java.lang.InstantiationException(\"bean ");
+ out.print(name);
+ out.println(" not found within scope\");");
+ } else {
+ /*
+ * Instantiate the bean if it is not in the specified scope.
+ */
+ if (!generateNew) {
+ String binaryName;
+ if (beanName != null) {
+ if (beanName.isNamedAttribute()) {
+ // If the value for beanName was specified via
+ // jsp:attribute, first generate code to evaluate
+ // that body.
+ binaryName = generateNamedAttributeValue(beanName
+ .getNamedAttributeNode());
+ } else {
+ binaryName = attributeValue(beanName, false,
+ String.class);
+ }
+ } else {
+ // Implies klass is not null
+ binaryName = quote(klass);
+ }
+ out.printil("try {");
+ out.pushIndent();
+ out.printin(name);
+ out.print(" = (");
+ out.print(type);
+ out.print(") java.beans.Beans.instantiate(");
+ out.print("this.getClass().getClassLoader(), ");
+ out.print(binaryName);
+ out.println(");");
+ out.popIndent();
+ /*
+ * Note: Beans.instantiate throws ClassNotFoundException if
+ * the bean class is abstract.
+ */
+ out.printil("} catch (ClassNotFoundException exc) {");
+ out.pushIndent();
+ out
+ .printil("throw new InstantiationException(exc.getMessage());");
+ out.popIndent();
+ out.printil("} catch (Exception exc) {");
+ out.pushIndent();
+ out.printin("throw new ServletException(");
+ out.print("\"Cannot create bean of class \" + ");
+ out.print(binaryName);
+ out.println(", exc);");
+ out.popIndent();
+ out.printil("}"); // close of try
+ } else {
+ // Implies klass is not null
+ // Generate codes to instantiate the bean class
+ out.printin(name);
+ out.print(" = new ");
+ out.print(canonicalName);
+ out.println("();");
+ }
+ /*
+ * Set attribute for bean in the specified scope
+ */
+ out.printin("_jspx_page_context.setAttribute(");
+ out.print(quote(name));
+ out.print(", ");
+ out.print(name);
+ out.print(", ");
+ out.print(scopename);
+ out.println(");");
+
+ // Only visit the body when bean is instantiated
+ visitBody(n);
+ }
+ out.popIndent();
+ out.printil("}");
+
+ // End of lock block
+ out.popIndent();
+ out.printil("}");
+
+ n.setEndJavaLine(out.getJavaLine());
+ }
+
+ /**
+ * @return a string for the form 'attr = "value"'
+ */
+ private String makeAttr(String attr, String value) {
+ if (value == null)
+ return "";
+
+ return " " + attr + "=\"" + value + '\"';
+ }
+
+ public void visit(Node.PlugIn n) throws JasperException {
+
+ /**
+ * A visitor to handle <jsp:param> in a plugin
+ */
+ class ParamVisitor extends Node.Visitor {
+
+ private boolean ie;
+
+ ParamVisitor(boolean ie) {
+ this.ie = ie;
+ }
+
+ public void visit(Node.ParamAction n) throws JasperException {
+
+ String name = n.getTextAttribute("name");
+ if (name.equalsIgnoreCase("object"))
+ name = "java_object";
+ else if (name.equalsIgnoreCase("type"))
+ name = "java_type";
+
+ n.setBeginJavaLine(out.getJavaLine());
+ // XXX - Fixed a bug here - value used to be output
+ // inline, which is only okay if value is not an EL
+ // expression. Also, key/value pairs for the
+ // embed tag were not being generated correctly.
+ // Double check that this is now the correct behavior.
+ if (ie) {
+ // We want something of the form
+ // out.println( "<param name=\"blah\"
+ // value=\"" + ... + "\">" );
+ out.printil("out.write( \"<param name=\\\""
+ + escape(name)
+ + "\\\" value=\\\"\" + "
+ + attributeValue(n.getValue(), false,
+ String.class) + " + \"\\\">\" );");
+ out.printil("out.write(\"\\n\");");
+ } else {
+ // We want something of the form
+ // out.print( " blah=\"" + ... + "\"" );
+ out.printil("out.write( \" "
+ + escape(name)
+ + "=\\\"\" + "
+ + attributeValue(n.getValue(), false,
+ String.class) + " + \"\\\"\" );");
+ }
+
+ n.setEndJavaLine(out.getJavaLine());
+ }
+ }
+
+ String type = n.getTextAttribute("type");
+ String code = n.getTextAttribute("code");
+ String name = n.getTextAttribute("name");
+ Node.JspAttribute height = n.getHeight();
+ Node.JspAttribute width = n.getWidth();
+ String hspace = n.getTextAttribute("hspace");
+ String vspace = n.getTextAttribute("vspace");
+ String align = n.getTextAttribute("align");
+ String iepluginurl = n.getTextAttribute("iepluginurl");
+ String nspluginurl = n.getTextAttribute("nspluginurl");
+ String codebase = n.getTextAttribute("codebase");
+ String archive = n.getTextAttribute("archive");
+ String jreversion = n.getTextAttribute("jreversion");
+
+ String widthStr = null;
+ if (width != null) {
+ if (width.isNamedAttribute()) {
+ widthStr = generateNamedAttributeValue(width
+ .getNamedAttributeNode());
+ } else {
+ widthStr = attributeValue(width, false, String.class);
+ }
+ }
+
+ String heightStr = null;
+ if (height != null) {
+ if (height.isNamedAttribute()) {
+ heightStr = generateNamedAttributeValue(height
+ .getNamedAttributeNode());
+ } else {
+ heightStr = attributeValue(height, false, String.class);
+ }
+ }
+
+ if (iepluginurl == null)
+ iepluginurl = Constants.IE_PLUGIN_URL;
+ if (nspluginurl == null)
+ nspluginurl = Constants.NS_PLUGIN_URL;
+
+ n.setBeginJavaLine(out.getJavaLine());
+
+ // If any of the params have their values specified by
+ // jsp:attribute, prepare those values first.
+ // Look for a params node and prepare its param subelements:
+ Node.JspBody jspBody = findJspBody(n);
+ if (jspBody != null) {
+ Node.Nodes subelements = jspBody.getBody();
+ if (subelements != null) {
+ for (int i = 0; i < subelements.size(); i++) {
+ Node m = subelements.getNode(i);
+ if (m instanceof Node.ParamsAction) {
+ prepareParams(m);
+ break;
+ }
+ }
+ }
+ }
+
+ // XXX - Fixed a bug here - width and height can be set
+ // dynamically. Double-check if this generation is correct.
+
+ // IE style plugin
+ // <object ...>
+ // First compose the runtime output string
+ String s0 = "<object"
+ + makeAttr("classid", ctxt.getOptions().getIeClassId())
+ + makeAttr("name", name);
+
+ String s1 = "";
+ if (width != null) {
+ s1 = " + \" width=\\\"\" + " + widthStr + " + \"\\\"\"";
+ }
+
+ String s2 = "";
+ if (height != null) {
+ s2 = " + \" height=\\\"\" + " + heightStr + " + \"\\\"\"";
+ }
+
+ String s3 = makeAttr("hspace", hspace) + makeAttr("vspace", vspace)
+ + makeAttr("align", align)
+ + makeAttr("codebase", iepluginurl) + '>';
+
+ // Then print the output string to the java file
+ out.printil("out.write(" + quote(s0) + s1 + s2 + " + " + quote(s3)
+ + ");");
+ out.printil("out.write(\"\\n\");");
+
+ // <param > for java_code
+ s0 = "<param name=\"java_code\"" + makeAttr("value", code) + '>';
+ out.printil("out.write(" + quote(s0) + ");");
+ out.printil("out.write(\"\\n\");");
+
+ // <param > for java_codebase
+ if (codebase != null) {
+ s0 = "<param name=\"java_codebase\""
+ + makeAttr("value", codebase) + '>';
+ out.printil("out.write(" + quote(s0) + ");");
+ out.printil("out.write(\"\\n\");");
+ }
+
+ // <param > for java_archive
+ if (archive != null) {
+ s0 = "<param name=\"java_archive\""
+ + makeAttr("value", archive) + '>';
+ out.printil("out.write(" + quote(s0) + ");");
+ out.printil("out.write(\"\\n\");");
+ }
+
+ // <param > for type
+ s0 = "<param name=\"type\""
+ + makeAttr("value", "application/x-java-"
+ + type
+ + ((jreversion == null) ? "" : ";version="
+ + jreversion)) + '>';
+ out.printil("out.write(" + quote(s0) + ");");
+ out.printil("out.write(\"\\n\");");
+
+ /*
+ * generate a <param> for each <jsp:param> in the plugin body
+ */
+ if (n.getBody() != null)
+ n.getBody().visit(new ParamVisitor(true));
+
+ /*
+ * Netscape style plugin part
+ */
+ out.printil("out.write(" + quote("<comment>") + ");");
+ out.printil("out.write(\"\\n\");");
+ s0 = "<EMBED"
+ + makeAttr("type", "application/x-java-"
+ + type
+ + ((jreversion == null) ? "" : ";version="
+ + jreversion)) + makeAttr("name", name);
+
+ // s1 and s2 are the same as before.
+
+ s3 = makeAttr("hspace", hspace) + makeAttr("vspace", vspace)
+ + makeAttr("align", align)
+ + makeAttr("pluginspage", nspluginurl)
+ + makeAttr("java_code", code)
+ + makeAttr("java_codebase", codebase)
+ + makeAttr("java_archive", archive);
+ out.printil("out.write(" + quote(s0) + s1 + s2 + " + " + quote(s3)
+ + ");");
+
+ /*
+ * Generate a 'attr = "value"' for each <jsp:param> in plugin body
+ */
+ if (n.getBody() != null)
+ n.getBody().visit(new ParamVisitor(false));
+
+ out.printil("out.write(" + quote("/>") + ");");
+ out.printil("out.write(\"\\n\");");
+
+ out.printil("out.write(" + quote("<noembed>") + ");");
+ out.printil("out.write(\"\\n\");");
+
+ /*
+ * Fallback
+ */
+ if (n.getBody() != null) {
+ visitBody(n);
+ out.printil("out.write(\"\\n\");");
+ }
+
+ out.printil("out.write(" + quote("</noembed>") + ");");
+ out.printil("out.write(\"\\n\");");
+
+ out.printil("out.write(" + quote("</comment>") + ");");
+ out.printil("out.write(\"\\n\");");
+
+ out.printil("out.write(" + quote("</object>") + ");");
+ out.printil("out.write(\"\\n\");");
+
+ n.setEndJavaLine(out.getJavaLine());
+ }
+
+ public void visit(Node.NamedAttribute n) throws JasperException {
+ // Don't visit body of this tag - we already did earlier.
+ }
+
+ public void visit(Node.CustomTag n) throws JasperException {
+
+ // Use plugin to generate more efficient code if there is one.
+ if (n.useTagPlugin()) {
+ generateTagPlugin(n);
+ return;
+ }
+
+ TagHandlerInfo handlerInfo = getTagHandlerInfo(n);
+
+ // Create variable names
+ String baseVar = createTagVarName(n.getQName(), n.getPrefix(), n
+ .getLocalName());
+ String tagEvalVar = "_jspx_eval_" + baseVar;
+ String tagHandlerVar = "_jspx_th_" + baseVar;
+ String tagPushBodyCountVar = "_jspx_push_body_count_" + baseVar;
+
+ // If the tag contains no scripting element, generate its codes
+ // to a method.
+ ServletWriter outSave = null;
+ Node.ChildInfo ci = n.getChildInfo();
+ if (ci.isScriptless() && !ci.hasScriptingVars()) {
+ // The tag handler and its body code can reside in a separate
+ // method if it is scriptless and does not have any scripting
+ // variable defined.
+
+ String tagMethod = "_jspx_meth_" + baseVar;
+
+ // Generate a call to this method
+ out.printin("if (");
+ out.print(tagMethod);
+ out.print("(");
+ if (parent != null) {
+ out.print(parent);
+ out.print(", ");
+ }
+ out.print("_jspx_page_context");
+ if (pushBodyCountVar != null) {
+ out.print(", ");
+ out.print(pushBodyCountVar);
+ }
+ out.println("))");
+ out.pushIndent();
+ out.printil((methodNesting > 0) ? "return true;" : "return;");
+ out.popIndent();
+
+ // Set up new buffer for the method
+ outSave = out;
+ /*
+ * For fragments, their bodies will be generated in fragment
+ * helper classes, and the Java line adjustments will be done
+ * there, hence they are set to null here to avoid double
+ * adjustments.
+ */
+ GenBuffer genBuffer = new GenBuffer(n,
+ n.implementsSimpleTag() ? null : n.getBody());
+ methodsBuffered.add(genBuffer);
+ out = genBuffer.getOut();
+
+ methodNesting++;
+ // Generate code for method declaration
+ out.println();
+ out.pushIndent();
+ out.printin("private boolean ");
+ out.print(tagMethod);
+ out.print("(");
+ if (parent != null) {
+ out.print("javax.servlet.jsp.tagext.JspTag ");
+ out.print(parent);
+ out.print(", ");
+ }
+ out.print("PageContext _jspx_page_context");
+ if (pushBodyCountVar != null) {
+ out.print(", int[] ");
+ out.print(pushBodyCountVar);
+ }
+ out.println(")");
+ out.printil(" throws Throwable {");
+ out.pushIndent();
+
+ // Initilaize local variables used in this method.
+ if (!isTagFile) {
+ out
+ .printil("PageContext pageContext = _jspx_page_context;");
+ }
+ out.printil("JspWriter out = _jspx_page_context.getOut();");
+ generateLocalVariables(out, n);
+ }
+
+ if (n.implementsSimpleTag()) {
+ generateCustomDoTag(n, handlerInfo, tagHandlerVar);
+ } else {
+ /*
+ * Classic tag handler: Generate code for start element, body,
+ * and end element
+ */
+ generateCustomStart(n, handlerInfo, tagHandlerVar, tagEvalVar,
+ tagPushBodyCountVar);
+
+ // visit body
+ String tmpParent = parent;
+ parent = tagHandlerVar;
+ boolean isSimpleTagParentSave = isSimpleTagParent;
+ isSimpleTagParent = false;
+ String tmpPushBodyCountVar = null;
+ if (n.implementsTryCatchFinally()) {
+ tmpPushBodyCountVar = pushBodyCountVar;
+ pushBodyCountVar = tagPushBodyCountVar;
+ }
+ boolean tmpIsSimpleTagHandler = isSimpleTagHandler;
+ isSimpleTagHandler = false;
+
+ visitBody(n);
+
+ parent = tmpParent;
+ isSimpleTagParent = isSimpleTagParentSave;
+ if (n.implementsTryCatchFinally()) {
+ pushBodyCountVar = tmpPushBodyCountVar;
+ }
+ isSimpleTagHandler = tmpIsSimpleTagHandler;
+
+ generateCustomEnd(n, tagHandlerVar, tagEvalVar,
+ tagPushBodyCountVar);
+ }
+
+ if (ci.isScriptless() && !ci.hasScriptingVars()) {
+ // Generate end of method
+ if (methodNesting > 0) {
+ out.printil("return false;");
+ }
+ out.popIndent();
+ out.printil("}");
+ out.popIndent();
+
+ methodNesting--;
+
+ // restore previous writer
+ out = outSave;
+ }
+ }
+
+ private static final String SINGLE_QUOTE = "'";
+
+ private static final String DOUBLE_QUOTE = "\\\"";
+
+ public void visit(Node.UninterpretedTag n) throws JasperException {
+
+ n.setBeginJavaLine(out.getJavaLine());
+
+ /*
+ * Write begin tag
+ */
+ out.printin("out.write(\"<");
+ out.print(n.getQName());
+
+ Attributes attrs = n.getNonTaglibXmlnsAttributes();
+ int attrsLen = (attrs == null) ? 0 : attrs.getLength();
+ for (int i = 0; i < attrsLen; i++) {
+ out.print(" ");
+ out.print(attrs.getQName(i));
+ out.print("=");
+ out.print(DOUBLE_QUOTE);
+ out.print(attrs.getValue(i).replace("\"", """));
+ out.print(DOUBLE_QUOTE);
+ }
+
+ attrs = n.getAttributes();
+ attrsLen = (attrs == null) ? 0 : attrs.getLength();
+ Node.JspAttribute[] jspAttrs = n.getJspAttributes();
+ for (int i = 0; i < attrsLen; i++) {
+ out.print(" ");
+ out.print(attrs.getQName(i));
+ out.print("=");
+ if (jspAttrs[i].isELInterpreterInput()) {
+ out.print("\\\"\" + ");
+ out.print(attributeValue(jspAttrs[i], false, String.class));
+ out.print(" + \"\\\"");
+ } else {
+ out.print(DOUBLE_QUOTE);
+ out.print(attrs.getValue(i).replace("\"", """));
+ out.print(DOUBLE_QUOTE);
+ }
+ }
+
+ if (n.getBody() != null) {
+ out.println(">\");");
+
+ // Visit tag body
+ visitBody(n);
+
+ /*
+ * Write end tag
+ */
+ out.printin("out.write(\"</");
+ out.print(n.getQName());
+ out.println(">\");");
+ } else {
+ out.println("/>\");");
+ }
+
+ n.setEndJavaLine(out.getJavaLine());
+ }
+
+ public void visit(Node.JspElement n) throws JasperException {
+
+ n.setBeginJavaLine(out.getJavaLine());
+
+ // Compute attribute value string for XML-style and named
+ // attributes
+ Hashtable map = new Hashtable();
+ Node.JspAttribute[] attrs = n.getJspAttributes();
+ for (int i = 0; attrs != null && i < attrs.length; i++) {
+ String attrStr = null;
+ if (attrs[i].isNamedAttribute()) {
+ attrStr = generateNamedAttributeValue(attrs[i]
+ .getNamedAttributeNode());
+ } else {
+ attrStr = attributeValue(attrs[i], false, Object.class);
+ }
+ String s = " + \" " + attrs[i].getName() + "=\\\"\" + "
+ + attrStr + " + \"\\\"\"";
+ map.put(attrs[i].getName(), s);
+ }
+
+ // Write begin tag, using XML-style 'name' attribute as the
+ // element name
+ String elemName = attributeValue(n.getNameAttribute(), false,
+ String.class);
+ out.printin("out.write(\"<\"");
+ out.print(" + " + elemName);
+
+ // Write remaining attributes
+ Enumeration enumeration = map.keys();
+ while (enumeration.hasMoreElements()) {
+ String attrName = (String) enumeration.nextElement();
+ out.print((String) map.get(attrName));
+ }
+
+ // Does the <jsp:element> have nested tags other than
+ // <jsp:attribute>
+ boolean hasBody = false;
+ Node.Nodes subelements = n.getBody();
+ if (subelements != null) {
+ for (int i = 0; i < subelements.size(); i++) {
+ Node subelem = subelements.getNode(i);
+ if (!(subelem instanceof Node.NamedAttribute)) {
+ hasBody = true;
+ break;
+ }
+ }
+ }
+ if (hasBody) {
+ out.println(" + \">\");");
+
+ // Smap should not include the body
+ n.setEndJavaLine(out.getJavaLine());
+
+ // Visit tag body
+ visitBody(n);
+
+ // Write end tag
+ out.printin("out.write(\"</\"");
+ out.print(" + " + elemName);
+ out.println(" + \">\");");
+ } else {
+ out.println(" + \"/>\");");
+ n.setEndJavaLine(out.getJavaLine());
+ }
+ }
+
+ public void visit(Node.TemplateText n) throws JasperException {
+
+ String text = n.getText();
+
+ int textSize = text.length();
+ if (textSize == 0) {
+ return;
+ }
+
+ if (textSize <= 3) {
+ // Special case small text strings
+ n.setBeginJavaLine(out.getJavaLine());
+ int lineInc = 0;
+ for (int i = 0; i < textSize; i++) {
+ char ch = text.charAt(i);
+ out.printil("out.write(" + quote(ch) + ");");
+ if (i > 0) {
+ n.addSmap(lineInc);
+ }
+ if (ch == '\n') {
+ lineInc++;
+ }
+ }
+ n.setEndJavaLine(out.getJavaLine());
+ return;
+ }
+
+ if (ctxt.getOptions().genStringAsCharArray()) {
+ // Generate Strings as char arrays, for performance
+ ServletWriter caOut;
+ if (charArrayBuffer == null) {
+ charArrayBuffer = new GenBuffer();
+ caOut = charArrayBuffer.getOut();
+ caOut.pushIndent();
+ textMap = new HashMap();
+ } else {
+ caOut = charArrayBuffer.getOut();
+ }
+ String charArrayName = (String) textMap.get(text);
+ if (charArrayName == null) {
+ charArrayName = "_jspx_char_array_" + charArrayCount++;
+ textMap.put(text, charArrayName);
+ caOut.printin("static char[] ");
+ caOut.print(charArrayName);
+ caOut.print(" = ");
+ caOut.print(quote(text));
+ caOut.println(".toCharArray();");
+ }
+
+ n.setBeginJavaLine(out.getJavaLine());
+ out.printil("out.write(" + charArrayName + ");");
+ n.setEndJavaLine(out.getJavaLine());
+ return;
+ }
+
+ n.setBeginJavaLine(out.getJavaLine());
+
+ out.printin();
+ StringBuffer sb = new StringBuffer("out.write(\"");
+ int initLength = sb.length();
+ int count = JspUtil.CHUNKSIZE;
+ int srcLine = 0; // relative to starting srouce line
+ for (int i = 0; i < text.length(); i++) {
+ char ch = text.charAt(i);
+ --count;
+ switch (ch) {
+ case '"':
+ sb.append('\\').append('\"');
+ break;
+ case '\\':
+ sb.append('\\').append('\\');
+ break;
+ case '\r':
+ sb.append('\\').append('r');
+ break;
+ case '\n':
+ sb.append('\\').append('n');
+ srcLine++;
+
+ if (breakAtLF || count < 0) {
+ // Generate an out.write() when see a '\n' in template
+ sb.append("\");");
+ out.println(sb.toString());
+ if (i < text.length() - 1) {
+ out.printin();
+ }
+ sb.setLength(initLength);
+ count = JspUtil.CHUNKSIZE;
+ }
+ // add a Smap for this line
+ n.addSmap(srcLine);
+ break;
+ case '\t': // Not sure we need this
+ sb.append('\\').append('t');
+ break;
+ default:
+ sb.append(ch);
+ }
+ }
+
+ if (sb.length() > initLength) {
+ sb.append("\");");
+ out.println(sb.toString());
+ }
+
+ n.setEndJavaLine(out.getJavaLine());
+ }
+
+ public void visit(Node.JspBody n) throws JasperException {
+ if (n.getBody() != null) {
+ if (isSimpleTagHandler) {
+ out.printin(simpleTagHandlerVar);
+ out.print(".setJspBody(");
+ generateJspFragment(n, simpleTagHandlerVar);
+ out.println(");");
+ } else {
+ visitBody(n);
+ }
+ }
+ }
+
+ public void visit(Node.InvokeAction n) throws JasperException {
+
+ n.setBeginJavaLine(out.getJavaLine());
+
+ // Copy virtual page scope of tag file to page scope of invoking
+ // page
+ out.printil("((org.apache.jasper.runtime.JspContextWrapper) this.jspContext).syncBeforeInvoke();");
+ String varReaderAttr = n.getTextAttribute("varReader");
+ String varAttr = n.getTextAttribute("var");
+ if (varReaderAttr != null || varAttr != null) {
+ out.printil("_jspx_sout = new java.io.StringWriter();");
+ } else {
+ out.printil("_jspx_sout = null;");
+ }
+
+ // Invoke fragment, unless fragment is null
+ out.printin("if (");
+ out.print(toGetterMethod(n.getTextAttribute("fragment")));
+ out.println(" != null) {");
+ out.pushIndent();
+ out.printin(toGetterMethod(n.getTextAttribute("fragment")));
+ out.println(".invoke(_jspx_sout);");
+ out.popIndent();
+ out.printil("}");
+
+ // Store varReader in appropriate scope
+ if (varReaderAttr != null || varAttr != null) {
+ String scopeName = n.getTextAttribute("scope");
+ out.printin("_jspx_page_context.setAttribute(");
+ if (varReaderAttr != null) {
+ out.print(quote(varReaderAttr));
+ out.print(", new java.io.StringReader(_jspx_sout.toString())");
+ } else {
+ out.print(quote(varAttr));
+ out.print(", _jspx_sout.toString()");
+ }
+ if (scopeName != null) {
+ out.print(", ");
+ out.print(getScopeConstant(scopeName));
+ }
+ out.println(");");
+ }
+
+ // Restore EL context
+ out.printil("jspContext.getELContext().putContext(JspContext.class,getJspContext());");
+
+ n.setEndJavaLine(out.getJavaLine());
+ }
+
+ public void visit(Node.DoBodyAction n) throws JasperException {
+
+ n.setBeginJavaLine(out.getJavaLine());
+
+ // Copy virtual page scope of tag file to page scope of invoking
+ // page
+ out.printil("((org.apache.jasper.runtime.JspContextWrapper) this.jspContext).syncBeforeInvoke();");
+
+ // Invoke body
+ String varReaderAttr = n.getTextAttribute("varReader");
+ String varAttr = n.getTextAttribute("var");
+ if (varReaderAttr != null || varAttr != null) {
+ out.printil("_jspx_sout = new java.io.StringWriter();");
+ } else {
+ out.printil("_jspx_sout = null;");
+ }
+ out.printil("if (getJspBody() != null)");
+ out.pushIndent();
+ out.printil("getJspBody().invoke(_jspx_sout);");
+ out.popIndent();
+
+ // Store varReader in appropriate scope
+ if (varReaderAttr != null || varAttr != null) {
+ String scopeName = n.getTextAttribute("scope");
+ out.printin("_jspx_page_context.setAttribute(");
+ if (varReaderAttr != null) {
+ out.print(quote(varReaderAttr));
+ out
+ .print(", new java.io.StringReader(_jspx_sout.toString())");
+ } else {
+ out.print(quote(varAttr));
+ out.print(", _jspx_sout.toString()");
+ }
+ if (scopeName != null) {
+ out.print(", ");
+ out.print(getScopeConstant(scopeName));
+ }
+ out.println(");");
+ }
+
+ // Restore EL context
+ out.printil("jspContext.getELContext().putContext(JspContext.class,getJspContext());");
+
+ n.setEndJavaLine(out.getJavaLine());
+ }
+
+ public void visit(Node.AttributeGenerator n) throws JasperException {
+ Node.CustomTag tag = n.getTag();
+ Node.JspAttribute[] attrs = tag.getJspAttributes();
+ for (int i = 0; attrs != null && i < attrs.length; i++) {
+ if (attrs[i].getName().equals(n.getName())) {
+ out.print(evaluateAttribute(getTagHandlerInfo(tag),
+ attrs[i], tag, null));
+ break;
+ }
+ }
+ }
+
+ private TagHandlerInfo getTagHandlerInfo(Node.CustomTag n)
+ throws JasperException {
+ Hashtable handlerInfosByShortName = (Hashtable) handlerInfos.get(n
+ .getPrefix());
+ if (handlerInfosByShortName == null) {
+ handlerInfosByShortName = new Hashtable();
+ handlerInfos.put(n.getPrefix(), handlerInfosByShortName);
+ }
+ TagHandlerInfo handlerInfo = (TagHandlerInfo) handlerInfosByShortName
+ .get(n.getLocalName());
+ if (handlerInfo == null) {
+ handlerInfo = new TagHandlerInfo(n, n.getTagHandlerClass(), err);
+ handlerInfosByShortName.put(n.getLocalName(), handlerInfo);
+ }
+ return handlerInfo;
+ }
+
+ private void generateTagPlugin(Node.CustomTag n) throws JasperException {
+ if (n.getAtSTag() != null) {
+ n.getAtSTag().visit(this);
+ }
+ visitBody(n);
+ if (n.getAtETag() != null) {
+ n.getAtETag().visit(this);
+ }
+ }
+
+ private void generateCustomStart(Node.CustomTag n,
+ TagHandlerInfo handlerInfo, String tagHandlerVar,
+ String tagEvalVar, String tagPushBodyCountVar)
+ throws JasperException {
+
+ Class tagHandlerClass = handlerInfo.getTagHandlerClass();
+
+ out.printin("// ");
+ out.println(n.getQName());
+ n.setBeginJavaLine(out.getJavaLine());
+
+ // Declare AT_BEGIN scripting variables
+ declareScriptingVars(n, VariableInfo.AT_BEGIN);
+ saveScriptingVars(n, VariableInfo.AT_BEGIN);
+
+ String tagHandlerClassName = JspUtil
+ .getCanonicalName(tagHandlerClass);
+ out.printin(tagHandlerClassName);
+ out.print(" ");
+ out.print(tagHandlerVar);
+ out.print(" = ");
+ if (isPoolingEnabled && !(n.implementsJspIdConsumer())) {
+ out.print("(");
+ out.print(tagHandlerClassName);
+ out.print(") ");
+ out.print(n.getTagHandlerPoolName());
+ out.print(".get(");
+ out.print(tagHandlerClassName);
+ out.println(".class);");
+ } else {
+ out.print("new ");
+ out.print(tagHandlerClassName);
+ out.println("();");
+ out.printin("org.apache.jasper.runtime.AnnotationHelper.postConstruct(");
+ out.print(VAR_ANNOTATIONPROCESSOR);
+ out.print(", ");
+ out.print(tagHandlerVar);
+ out.println(");");
+ }
+
+ // includes setting the context
+ generateSetters(n, tagHandlerVar, handlerInfo, false);
+
+ // JspIdConsumer (after context has been set)
+ if (n.implementsJspIdConsumer()) {
+ out.printin(tagHandlerVar);
+ out.print(".setJspId(\"");
+ out.print(createJspId());
+ out.println("\");");
+ }
+
+ if (n.implementsTryCatchFinally()) {
+ out.printin("int[] ");
+ out.print(tagPushBodyCountVar);
+ out.println(" = new int[] { 0 };");
+ out.printil("try {");
+ out.pushIndent();
+ }
+ out.printin("int ");
+ out.print(tagEvalVar);
+ out.print(" = ");
+ out.print(tagHandlerVar);
+ out.println(".doStartTag();");
+
+ if (!n.implementsBodyTag()) {
+ // Synchronize AT_BEGIN scripting variables
+ syncScriptingVars(n, VariableInfo.AT_BEGIN);
+ }
+
+ if (!n.hasEmptyBody()) {
+ out.printin("if (");
+ out.print(tagEvalVar);
+ out.println(" != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {");
+ out.pushIndent();
+
+ // Declare NESTED scripting variables
+ declareScriptingVars(n, VariableInfo.NESTED);
+ saveScriptingVars(n, VariableInfo.NESTED);
+
+ if (n.implementsBodyTag()) {
+ out.printin("if (");
+ out.print(tagEvalVar);
+ out
+ .println(" != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {");
+ // Assume EVAL_BODY_BUFFERED
+ out.pushIndent();
+ out.printil("out = _jspx_page_context.pushBody();");
+ if (n.implementsTryCatchFinally()) {
+ out.printin(tagPushBodyCountVar);
[... 1924 lines stripped ...]