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/07/31 20:12:51 UTC
svn commit: r799681 [4/24] - in /struts/sandbox/trunk/struts2-jsp-plugin: ./
src/main/java/org/apache/struts/ src/main/java/org/apache/struts2/
src/main/java/org/apache/struts2/compiler/
src/main/java/org/apache/struts2/jasper/ src/main/java/org/apache...
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/Generator.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/Generator.java?rev=799681&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/Generator.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/Generator.java Fri Jul 31 18:12:48 2009
@@ -0,0 +1,4063 @@
+/*
+ * 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 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.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.struts2.jasper.Constants;
+import org.apache.struts2.jasper.JasperException;
+import org.apache.struts2.jasper.JspCompilationContext;
+import org.apache.struts2.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
+ */
+
+class Generator {
+
+ private static final Class[] OBJECT_CLASS = { Object.class };
+ 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 PageInfo pageInfo;
+ private Vector 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();
+ }
+
+ /**
+ * 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.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,
+ boolean hasEmptyBody) {
+ String poolName = null;
+
+ poolName = "_jspx_tagPool_" + prefix + "_" + shortName;
+ if (attrs != null) {
+ String[] attrNames = new String[attrs.getLength()];
+ for (int i = 0; i < attrNames.length; i++) {
+ attrNames[i] = attrs.getQName(i);
+ }
+ 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.
+ */
+ private void generateInit() {
+
+ if (ctxt.isTagFile()) {
+ out.printil("private void _jspInit(ServletConfig config) {");
+ } else {
+ out.printil("public void _jspInit() {");
+ }
+
+ out.pushIndent();
+ for (int i = 0; i < tagHandlerPoolNames.size(); i++) {
+ out.printin((String)tagHandlerPoolNames.elementAt(i));
+ out.print(
+ " = org.apache.struts2.jasper.runtime.TagHandlerPool.getTagHandlerPool(");
+ if (ctxt.isTagFile()) {
+ out.print("config");
+ } else {
+ out.print("getServletConfig()");
+ }
+ out.println(");");
+ }
+ 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();
+ 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 {
+ // 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)
+ */
+ private void genPreambleClassVariableDeclarations(String className)
+ throws JasperException {
+ if (isPoolingEnabled && !tagHandlerPoolNames.isEmpty()) {
+ for (int i = 0; i < tagHandlerPoolNames.size(); i++) {
+ out.printil(
+ "private org.apache.struts2.jasper.runtime.TagHandlerPool "
+ + tagHandlerPoolNames.elementAt(i)
+ + ";");
+ }
+ 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();
+
+ if (isPoolingEnabled && !tagHandlerPoolNames.isEmpty()) {
+ 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.struts2.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("JspFactory _jspxFactory = null;");
+ out.printil("PageContext pageContext = null;");
+ if (pageInfo.isSession())
+ out.printil("HttpSession session = null;");
+
+ if (pageInfo.isErrorPage()) {
+ out.printil(
+ "Throwable exception = org.apache.struts2.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.printil("_jspxFactory = JspFactory.getDefaultFactory();");
+
+ out.printin("response.setContentType(");
+ out.print(quote(pageInfo.getContentType()));
+ out.println(");");
+
+ if (ctxt.getOptions().isXpoweredBy()) {
+ out.printil("response.addHeader(\"X-Powered-By\", \"JSP/2.0\");");
+ }
+
+ 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.struts2.jasper.runtime.JspRuntimeLibrary.URLEncode(String.valueOf("
+ + v
+ + "), request.getCharacterEncoding())";
+ }
+ return v;
+ } else if (attr.isELInterpreterInput()) {
+ boolean replaceESC = v.indexOf(Constants.HACK_CHAR) > 0;
+ v =
+ JspUtil.interpreterCall(
+ this.isTagFile,
+ v,
+ expectedType,
+ attr.getEL().getMapName(),
+ false);
+ // XXX hack replacement
+ if (replaceESC) {
+ v = "(" + v + ").replace(" + Constants.HACK_STR + ", '$')";
+ }
+ if (encode) {
+ return "org.apache.struts2.jasper.runtime.JspRuntimeLibrary.URLEncode("
+ + v
+ + ", request.getCharacterEncoding())";
+ }
+ return v;
+ } else if (attr.isNamedAttribute()) {
+ return attr.getNamedAttributeNode().getTemporaryVariableName();
+ } else {
+ if (encode) {
+ return "org.apache.struts2.jasper.runtime.JspRuntimeLibrary.URLEncode("
+ + quote(v)
+ + ", request.getCharacterEncoding())";
+ }
+ return quote(v);
+ }
+ }
+
+ /**
+ * 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.struts2.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()) {
+ out.printil(
+ "out.write("
+ + JspUtil.interpreterCall(
+ this.isTagFile,
+ "${" + new String(n.getText()) + "}",
+ String.class,
+ n.getEL().getMapName(),
+ false)
+ + ");");
+ } else {
+ out.printil(
+ "out.write("
+ + quote("${" + 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.struts2.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.struts2.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.struts2.jasper.runtime.JspRuntimeLibrary.toString"
+ + "(org.apache.struts2.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.struts2.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.struts2.jasper.runtime.JspRuntimeLibrary.introspecthelper("
+ + "_jspx_page_context.findAttribute(\""
+ + name
+ + "\"), \""
+ + property
+ + "\", request.getParameter(\""
+ + param
+ + "\"), "
+ + "request, \""
+ + param
+ + "\", false);");
+ } else if (value.isExpression()) {
+ out.printil(
+ "org.apache.struts2.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.struts2.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.struts2.jasper.runtime.JspRuntimeLibrary.introspecthelper("
+ + "_jspx_page_context.findAttribute(\""
+ + name
+ + "\"), \""
+ + property
+ + "\", "
+ + valueVarName
+ + ", null, null, false);");
+ } else {
+ out.printin(
+ "org.apache.struts2.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("=");
+ String quote = DOUBLE_QUOTE;
+ String value = attrs.getValue(i);
+ if (value.indexOf('"') != -1) {
+ quote = SINGLE_QUOTE;
+ }
+ out.print(quote);
+ out.print(value);
+ out.print(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 {
+ String quote = DOUBLE_QUOTE;
+ String value = attrs.getValue(i);
+ if (value.indexOf('"') != -1) {
+ quote = SINGLE_QUOTE;
+ }
+ out.print(quote);
+ out.print(value);
+ out.print(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;
+ }
+
+ // Replace marker for \$ sequence with correct sequence
+ if (text.indexOf(Constants.HACK_CHAR) > 0) {
+ if (pageInfo.isELIgnored()) {
+ text = text.replaceAll(String.valueOf(Constants.HACK_CHAR),
+ "\\\\\\$");
+ textSize++;
+ } else {
+ text = text.replace(Constants.HACK_CHAR, '$');
+ }
+ }
+
+ 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.struts2.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(");");
+ }
+
+ 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.struts2.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(");");
+ }
+
+ 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) {
+ 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("();");
+ }
+
+ generateSetters(n, tagHandlerVar, handlerInfo, false);
+
+ 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);
+ out.println("[0]++;");
+ } else if (pushBodyCountVar != null) {
+ out.printin(pushBodyCountVar);
+ out.println("[0]++;");
+ }
+ out.printin(tagHandlerVar);
+ out.println(
+ ".setBodyContent((javax.servlet.jsp.tagext.BodyContent) out);");
+ out.printin(tagHandlerVar);
+ out.println(".doInitBody();");
+
+ out.popIndent();
+ out.printil("}");
+
[... 1820 lines stripped ...]