0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package org.apache.jasper.compiler;
0019:
0020: import java.beans.BeanInfo;
0021: import java.beans.IntrospectionException;
0022: import java.beans.Introspector;
0023: import java.beans.PropertyDescriptor;
0024: import java.lang.reflect.Method;
0025: import java.lang.reflect.Modifier;
0026: import java.util.ArrayList;
0027: import java.util.Arrays;
0028: import java.util.Collections;
0029: import java.util.Enumeration;
0030: import java.util.Hashtable;
0031: import java.util.HashMap;
0032: import java.util.Iterator;
0033: import java.util.List;
0034: import java.util.Vector;
0035:
0036: import javax.el.MethodExpression;
0037: import javax.el.ValueExpression;
0038: import javax.servlet.jsp.tagext.TagAttributeInfo;
0039: import javax.servlet.jsp.tagext.TagInfo;
0040: import javax.servlet.jsp.tagext.TagVariableInfo;
0041: import javax.servlet.jsp.tagext.VariableInfo;
0042:
0043: import org.apache.jasper.Constants;
0044: import org.apache.jasper.JasperException;
0045: import org.apache.jasper.JspCompilationContext;
0046: import org.apache.jasper.runtime.JspRuntimeLibrary;
0047: import org.xml.sax.Attributes;
0048:
0049: /**
0050: * Generate Java source from Nodes
0051: *
0052: * @author Anil K. Vijendran
0053: * @author Danno Ferrin
0054: * @author Mandar Raje
0055: * @author Rajiv Mordani
0056: * @author Pierre Delisle
0057: *
0058: * Tomcat 4.1.x and Tomcat 5:
0059: * @author Kin-man Chung
0060: * @author Jan Luehe
0061: * @author Shawn Bayern
0062: * @author Mark Roth
0063: * @author Denis Benoit
0064: *
0065: * Tomcat 6.x
0066: * @author Jacob Hookom
0067: * @author Remy Maucherat
0068: */
0069:
0070: class Generator {
0071:
0072: private static final Class[] OBJECT_CLASS = { Object.class };
0073:
0074: private static final String VAR_EXPRESSIONFACTORY = System
0075: .getProperty(
0076: "org.apache.jasper.compiler.Generator.VAR_EXPRESSIONFACTORY",
0077: "_el_expressionfactory");
0078: private static final String VAR_ANNOTATIONPROCESSOR = System
0079: .getProperty(
0080: "org.apache.jasper.compiler.Generator.VAR_ANNOTATIONPROCESSOR",
0081: "_jsp_annotationprocessor");
0082:
0083: private ServletWriter out;
0084:
0085: private ArrayList methodsBuffered;
0086:
0087: private FragmentHelperClass fragmentHelperClass;
0088:
0089: private ErrorDispatcher err;
0090:
0091: private BeanRepository beanInfo;
0092:
0093: private JspCompilationContext ctxt;
0094:
0095: private boolean isPoolingEnabled;
0096:
0097: private boolean breakAtLF;
0098:
0099: private String jspIdPrefix;
0100:
0101: private int jspId;
0102:
0103: private PageInfo pageInfo;
0104:
0105: private Vector<String> tagHandlerPoolNames;
0106:
0107: private GenBuffer charArrayBuffer;
0108:
0109: /**
0110: * @param s
0111: * the input string
0112: * @return quoted and escaped string, per Java rule
0113: */
0114: static String quote(String s) {
0115:
0116: if (s == null)
0117: return "null";
0118:
0119: return '"' + escape(s) + '"';
0120: }
0121:
0122: /**
0123: * @param s
0124: * the input string
0125: * @return escaped string, per Java rule
0126: */
0127: static String escape(String s) {
0128:
0129: if (s == null)
0130: return "";
0131:
0132: StringBuffer b = new StringBuffer();
0133: for (int i = 0; i < s.length(); i++) {
0134: char c = s.charAt(i);
0135: if (c == '"')
0136: b.append('\\').append('"');
0137: else if (c == '\\')
0138: b.append('\\').append('\\');
0139: else if (c == '\n')
0140: b.append('\\').append('n');
0141: else if (c == '\r')
0142: b.append('\\').append('r');
0143: else
0144: b.append(c);
0145: }
0146: return b.toString();
0147: }
0148:
0149: /**
0150: * Single quote and escape a character
0151: */
0152: static String quote(char c) {
0153:
0154: StringBuffer b = new StringBuffer();
0155: b.append('\'');
0156: if (c == '\'')
0157: b.append('\\').append('\'');
0158: else if (c == '\\')
0159: b.append('\\').append('\\');
0160: else if (c == '\n')
0161: b.append('\\').append('n');
0162: else if (c == '\r')
0163: b.append('\\').append('r');
0164: else
0165: b.append(c);
0166: b.append('\'');
0167: return b.toString();
0168: }
0169:
0170: private String createJspId() throws JasperException {
0171: if (this .jspIdPrefix == null) {
0172: StringBuffer sb = new StringBuffer(32);
0173: String name = ctxt.getServletJavaFileName();
0174: sb.append("jsp_").append(Math.abs(name.hashCode())).append(
0175: '_');
0176: this .jspIdPrefix = sb.toString();
0177: }
0178: return this .jspIdPrefix + (this .jspId++);
0179: }
0180:
0181: /**
0182: * Generates declarations. This includes "info" of the page directive, and
0183: * scriptlet declarations.
0184: */
0185: private void generateDeclarations(Node.Nodes page)
0186: throws JasperException {
0187:
0188: class DeclarationVisitor extends Node.Visitor {
0189:
0190: private boolean getServletInfoGenerated = false;
0191:
0192: /*
0193: * Generates getServletInfo() method that returns the value of the
0194: * page directive's 'info' attribute, if present.
0195: *
0196: * The Validator has already ensured that if the translation unit
0197: * contains more than one page directive with an 'info' attribute,
0198: * their values match.
0199: */
0200: public void visit(Node.PageDirective n)
0201: throws JasperException {
0202:
0203: if (getServletInfoGenerated) {
0204: return;
0205: }
0206:
0207: String info = n.getAttributeValue("info");
0208: if (info == null)
0209: return;
0210:
0211: getServletInfoGenerated = true;
0212: out.printil("public String getServletInfo() {");
0213: out.pushIndent();
0214: out.printin("return ");
0215: out.print(quote(info));
0216: out.println(";");
0217: out.popIndent();
0218: out.printil("}");
0219: out.println();
0220: }
0221:
0222: public void visit(Node.Declaration n)
0223: throws JasperException {
0224: n.setBeginJavaLine(out.getJavaLine());
0225: out.printMultiLn(new String(n.getText()));
0226: out.println();
0227: n.setEndJavaLine(out.getJavaLine());
0228: }
0229:
0230: // Custom Tags may contain declarations from tag plugins.
0231: public void visit(Node.CustomTag n) throws JasperException {
0232: if (n.useTagPlugin()) {
0233: if (n.getAtSTag() != null) {
0234: n.getAtSTag().visit(this );
0235: }
0236: visitBody(n);
0237: if (n.getAtETag() != null) {
0238: n.getAtETag().visit(this );
0239: }
0240: } else {
0241: visitBody(n);
0242: }
0243: }
0244: }
0245:
0246: out.println();
0247: page.visit(new DeclarationVisitor());
0248: }
0249:
0250: /**
0251: * Compiles list of tag handler pool names.
0252: */
0253: private void compileTagHandlerPoolList(Node.Nodes page)
0254: throws JasperException {
0255:
0256: class TagHandlerPoolVisitor extends Node.Visitor {
0257:
0258: private Vector names;
0259:
0260: /*
0261: * Constructor
0262: *
0263: * @param v Vector of tag handler pool names to populate
0264: */
0265: TagHandlerPoolVisitor(Vector v) {
0266: names = v;
0267: }
0268:
0269: /*
0270: * Gets the name of the tag handler pool for the given custom tag
0271: * and adds it to the list of tag handler pool names unless it is
0272: * already contained in it.
0273: */
0274: public void visit(Node.CustomTag n) throws JasperException {
0275:
0276: if (!n.implements SimpleTag()) {
0277: String name = createTagHandlerPoolName(n
0278: .getPrefix(), n.getLocalName(), n
0279: .getAttributes(), n.hasEmptyBody());
0280: n.setTagHandlerPoolName(name);
0281: if (!names.contains(name)) {
0282: names.add(name);
0283: }
0284: }
0285: visitBody(n);
0286: }
0287:
0288: /*
0289: * Creates the name of the tag handler pool whose tag handlers may
0290: * be (re)used to service this action.
0291: *
0292: * @return The name of the tag handler pool
0293: */
0294: private String createTagHandlerPoolName(String prefix,
0295: String shortName, Attributes attrs,
0296: boolean hasEmptyBody) {
0297: String poolName = null;
0298:
0299: poolName = "_jspx_tagPool_" + prefix + "_" + shortName;
0300: if (attrs != null) {
0301: String[] attrNames = new String[attrs.getLength()];
0302: for (int i = 0; i < attrNames.length; i++) {
0303: attrNames[i] = attrs.getQName(i);
0304: }
0305: Arrays.sort(attrNames, Collections.reverseOrder());
0306: for (int i = 0; i < attrNames.length; i++) {
0307: poolName = poolName + "_" + attrNames[i];
0308: }
0309: }
0310: if (hasEmptyBody) {
0311: poolName = poolName + "_nobody";
0312: }
0313: return JspUtil.makeJavaIdentifier(poolName);
0314: }
0315: }
0316:
0317: page.visit(new TagHandlerPoolVisitor(tagHandlerPoolNames));
0318: }
0319:
0320: private void declareTemporaryScriptingVars(Node.Nodes page)
0321: throws JasperException {
0322:
0323: class ScriptingVarVisitor extends Node.Visitor {
0324:
0325: private Vector vars;
0326:
0327: ScriptingVarVisitor() {
0328: vars = new Vector();
0329: }
0330:
0331: public void visit(Node.CustomTag n) throws JasperException {
0332:
0333: if (n.getCustomNestingLevel() > 0) {
0334: TagVariableInfo[] tagVarInfos = n
0335: .getTagVariableInfos();
0336: VariableInfo[] varInfos = n.getVariableInfos();
0337:
0338: if (varInfos.length > 0) {
0339: for (int i = 0; i < varInfos.length; i++) {
0340: String varName = varInfos[i].getVarName();
0341: String tmpVarName = "_jspx_" + varName
0342: + "_" + n.getCustomNestingLevel();
0343: if (!vars.contains(tmpVarName)) {
0344: vars.add(tmpVarName);
0345: out.printin(varInfos[i].getClassName());
0346: out.print(" ");
0347: out.print(tmpVarName);
0348: out.print(" = ");
0349: out.print(null);
0350: out.println(";");
0351: }
0352: }
0353: } else {
0354: for (int i = 0; i < tagVarInfos.length; i++) {
0355: String varName = tagVarInfos[i]
0356: .getNameGiven();
0357: if (varName == null) {
0358: varName = n
0359: .getTagData()
0360: .getAttributeString(
0361: tagVarInfos[i]
0362: .getNameFromAttribute());
0363: } else if (tagVarInfos[i]
0364: .getNameFromAttribute() != null) {
0365: // alias
0366: continue;
0367: }
0368: String tmpVarName = "_jspx_" + varName
0369: + "_" + n.getCustomNestingLevel();
0370: if (!vars.contains(tmpVarName)) {
0371: vars.add(tmpVarName);
0372: out.printin(tagVarInfos[i]
0373: .getClassName());
0374: out.print(" ");
0375: out.print(tmpVarName);
0376: out.print(" = ");
0377: out.print(null);
0378: out.println(";");
0379: }
0380: }
0381: }
0382: }
0383:
0384: visitBody(n);
0385: }
0386: }
0387:
0388: page.visit(new ScriptingVarVisitor());
0389: }
0390:
0391: /**
0392: * Generates the _jspInit() method for instantiating the tag handler pools.
0393: * For tag file, _jspInit has to be invoked manually, and the ServletConfig
0394: * object explicitly passed.
0395: *
0396: * In JSP 2.1, we also instantiate an ExpressionFactory
0397: */
0398: private void generateInit() {
0399:
0400: if (ctxt.isTagFile()) {
0401: out
0402: .printil("private void _jspInit(ServletConfig config) {");
0403: } else {
0404: out.printil("public void _jspInit() {");
0405: }
0406:
0407: out.pushIndent();
0408: if (isPoolingEnabled) {
0409: for (int i = 0; i < tagHandlerPoolNames.size(); i++) {
0410: out.printin(tagHandlerPoolNames.elementAt(i));
0411: out
0412: .print(" = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(");
0413: if (ctxt.isTagFile()) {
0414: out.print("config");
0415: } else {
0416: out.print("getServletConfig()");
0417: }
0418: out.println(");");
0419: }
0420: }
0421:
0422: out.printin(VAR_EXPRESSIONFACTORY);
0423: out.print(" = _jspxFactory.getJspApplicationContext(");
0424: if (ctxt.isTagFile()) {
0425: out.print("config");
0426: } else {
0427: out.print("getServletConfig()");
0428: }
0429: out.println(".getServletContext()).getExpressionFactory();");
0430:
0431: out.printin(VAR_ANNOTATIONPROCESSOR);
0432: out.print(" = (org.apache.AnnotationProcessor) ");
0433: if (ctxt.isTagFile()) {
0434: out.print("config");
0435: } else {
0436: out.print("getServletConfig()");
0437: }
0438: out
0439: .println(".getServletContext().getAttribute(org.apache.AnnotationProcessor.class.getName());");
0440:
0441: out.popIndent();
0442: out.printil("}");
0443: out.println();
0444: }
0445:
0446: /**
0447: * Generates the _jspDestroy() method which is responsible for calling the
0448: * release() method on every tag handler in any of the tag handler pools.
0449: */
0450: private void generateDestroy() {
0451:
0452: out.printil("public void _jspDestroy() {");
0453: out.pushIndent();
0454:
0455: if (isPoolingEnabled) {
0456: for (int i = 0; i < tagHandlerPoolNames.size(); i++) {
0457: out.printin((String) tagHandlerPoolNames.elementAt(i));
0458: out.println(".release();");
0459: }
0460: }
0461:
0462: out.popIndent();
0463: out.printil("}");
0464: out.println();
0465: }
0466:
0467: /**
0468: * Generate preamble package name (shared by servlet and tag handler
0469: * preamble generation)
0470: */
0471: private void genPreamblePackage(String packageName)
0472: throws JasperException {
0473: if (!"".equals(packageName) && packageName != null) {
0474: out.printil("package " + packageName + ";");
0475: out.println();
0476: }
0477: }
0478:
0479: /**
0480: * Generate preamble imports (shared by servlet and tag handler preamble
0481: * generation)
0482: */
0483: private void genPreambleImports() throws JasperException {
0484: Iterator iter = pageInfo.getImports().iterator();
0485: while (iter.hasNext()) {
0486: out.printin("import ");
0487: out.print((String) iter.next());
0488: out.println(";");
0489: }
0490:
0491: out.println();
0492: }
0493:
0494: /**
0495: * Generation of static initializers in preamble. For example, dependant
0496: * list, el function map, prefix map. (shared by servlet and tag handler
0497: * preamble generation)
0498: */
0499: private void genPreambleStaticInitializers() throws JasperException {
0500: out
0501: .printil("private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();");
0502: out.println();
0503:
0504: // Static data for getDependants()
0505: out.printil("private static java.util.List _jspx_dependants;");
0506: out.println();
0507: List dependants = pageInfo.getDependants();
0508: Iterator iter = dependants.iterator();
0509: if (!dependants.isEmpty()) {
0510: out.printil("static {");
0511: out.pushIndent();
0512: out.printin("_jspx_dependants = new java.util.ArrayList(");
0513: out.print("" + dependants.size());
0514: out.println(");");
0515: while (iter.hasNext()) {
0516: out.printin("_jspx_dependants.add(\"");
0517: out.print((String) iter.next());
0518: out.println("\");");
0519: }
0520: out.popIndent();
0521: out.printil("}");
0522: out.println();
0523: }
0524: }
0525:
0526: /**
0527: * Declare tag handler pools (tags of the same type and with the same
0528: * attribute set share the same tag handler pool) (shared by servlet and tag
0529: * handler preamble generation)
0530: *
0531: * In JSP 2.1, we also scope an instance of ExpressionFactory
0532: */
0533: private void genPreambleClassVariableDeclarations(String className)
0534: throws JasperException {
0535: if (isPoolingEnabled && !tagHandlerPoolNames.isEmpty()) {
0536: for (int i = 0; i < tagHandlerPoolNames.size(); i++) {
0537: out
0538: .printil("private org.apache.jasper.runtime.TagHandlerPool "
0539: + tagHandlerPoolNames.elementAt(i)
0540: + ";");
0541: }
0542: out.println();
0543: }
0544: out.printin("private javax.el.ExpressionFactory ");
0545: out.print(VAR_EXPRESSIONFACTORY);
0546: out.println(";");
0547: out.printin("private org.apache.AnnotationProcessor ");
0548: out.print(VAR_ANNOTATIONPROCESSOR);
0549: out.println(";");
0550: out.println();
0551: }
0552:
0553: /**
0554: * Declare general-purpose methods (shared by servlet and tag handler
0555: * preamble generation)
0556: */
0557: private void genPreambleMethods() throws JasperException {
0558: // Method used to get compile time file dependencies
0559: out.printil("public Object getDependants() {");
0560: out.pushIndent();
0561: out.printil("return _jspx_dependants;");
0562: out.popIndent();
0563: out.printil("}");
0564: out.println();
0565:
0566: generateInit();
0567: generateDestroy();
0568: }
0569:
0570: /**
0571: * Generates the beginning of the static portion of the servlet.
0572: */
0573: private void generatePreamble(Node.Nodes page)
0574: throws JasperException {
0575:
0576: String servletPackageName = ctxt.getServletPackageName();
0577: String servletClassName = ctxt.getServletClassName();
0578: String serviceMethodName = Constants.SERVICE_METHOD_NAME;
0579:
0580: // First the package name:
0581: genPreamblePackage(servletPackageName);
0582:
0583: // Generate imports
0584: genPreambleImports();
0585:
0586: // Generate class declaration
0587: out.printin("public final class ");
0588: out.print(servletClassName);
0589: out.print(" extends ");
0590: out.println(pageInfo.getExtends());
0591: out
0592: .printin(" implements org.apache.jasper.runtime.JspSourceDependent");
0593: if (!pageInfo.isThreadSafe()) {
0594: out.println(",");
0595: out.printin(" SingleThreadModel");
0596: }
0597: out.println(" {");
0598: out.pushIndent();
0599:
0600: // Class body begins here
0601: generateDeclarations(page);
0602:
0603: // Static initializations here
0604: genPreambleStaticInitializers();
0605:
0606: // Class variable declarations
0607: genPreambleClassVariableDeclarations(servletClassName);
0608:
0609: // Constructor
0610: // generateConstructor(className);
0611:
0612: // Methods here
0613: genPreambleMethods();
0614:
0615: // Now the service method
0616: out.printin("public void ");
0617: out.print(serviceMethodName);
0618: out
0619: .println("(HttpServletRequest request, HttpServletResponse response)");
0620: out
0621: .println(" throws java.io.IOException, ServletException {");
0622:
0623: out.pushIndent();
0624: out.println();
0625:
0626: // Local variable declarations
0627: out.printil("PageContext pageContext = null;");
0628:
0629: if (pageInfo.isSession())
0630: out.printil("HttpSession session = null;");
0631:
0632: if (pageInfo.isErrorPage()) {
0633: out
0634: .printil("Throwable exception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request);");
0635: out.printil("if (exception != null) {");
0636: out.pushIndent();
0637: out
0638: .printil("response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);");
0639: out.popIndent();
0640: out.printil("}");
0641: }
0642:
0643: out.printil("ServletContext application = null;");
0644: out.printil("ServletConfig config = null;");
0645: out.printil("JspWriter out = null;");
0646: out.printil("Object page = this;");
0647:
0648: out.printil("JspWriter _jspx_out = null;");
0649: out.printil("PageContext _jspx_page_context = null;");
0650: out.println();
0651:
0652: declareTemporaryScriptingVars(page);
0653: out.println();
0654:
0655: out.printil("try {");
0656: out.pushIndent();
0657:
0658: out.printin("response.setContentType(");
0659: out.print(quote(pageInfo.getContentType()));
0660: out.println(");");
0661:
0662: if (ctxt.getOptions().isXpoweredBy()) {
0663: out
0664: .printil("response.addHeader(\"X-Powered-By\", \"JSP/2.1\");");
0665: }
0666:
0667: out
0668: .printil("pageContext = _jspxFactory.getPageContext(this, request, response,");
0669: out.printin("\t\t\t");
0670: out.print(quote(pageInfo.getErrorPage()));
0671: out.print(", " + pageInfo.isSession());
0672: out.print(", " + pageInfo.getBuffer());
0673: out.print(", " + pageInfo.isAutoFlush());
0674: out.println(");");
0675: out.printil("_jspx_page_context = pageContext;");
0676:
0677: out.printil("application = pageContext.getServletContext();");
0678: out.printil("config = pageContext.getServletConfig();");
0679:
0680: if (pageInfo.isSession())
0681: out.printil("session = pageContext.getSession();");
0682: out.printil("out = pageContext.getOut();");
0683: out.printil("_jspx_out = out;");
0684: out.println();
0685: }
0686:
0687: /**
0688: * Generates an XML Prolog, which includes an XML declaration and an XML
0689: * doctype declaration.
0690: */
0691: private void generateXmlProlog(Node.Nodes page) {
0692:
0693: /*
0694: * An XML declaration is generated under the following conditions: -
0695: * 'omit-xml-declaration' attribute of <jsp:output> action is set to
0696: * "no" or "false" - JSP document without a <jsp:root>
0697: */
0698: String omitXmlDecl = pageInfo.getOmitXmlDecl();
0699: if ((omitXmlDecl != null && !JspUtil.booleanValue(omitXmlDecl))
0700: || (omitXmlDecl == null && page.getRoot().isXmlSyntax()
0701: && !pageInfo.hasJspRoot() && !ctxt.isTagFile())) {
0702: String cType = pageInfo.getContentType();
0703: String charSet = cType
0704: .substring(cType.indexOf("charset=") + 8);
0705: out
0706: .printil("out.write(\"<?xml version=\\\"1.0\\\" encoding=\\\""
0707: + charSet + "\\\"?>\\n\");");
0708: }
0709:
0710: /*
0711: * Output a DOCTYPE declaration if the doctype-root-element appears. If
0712: * doctype-public appears: <!DOCTYPE name PUBLIC "doctypePublic"
0713: * "doctypeSystem"> else <!DOCTYPE name SYSTEM "doctypeSystem" >
0714: */
0715:
0716: String doctypeName = pageInfo.getDoctypeName();
0717: if (doctypeName != null) {
0718: String doctypePublic = pageInfo.getDoctypePublic();
0719: String doctypeSystem = pageInfo.getDoctypeSystem();
0720: out.printin("out.write(\"<!DOCTYPE ");
0721: out.print(doctypeName);
0722: if (doctypePublic == null) {
0723: out.print(" SYSTEM \\\"");
0724: } else {
0725: out.print(" PUBLIC \\\"");
0726: out.print(doctypePublic);
0727: out.print("\\\" \\\"");
0728: }
0729: out.print(doctypeSystem);
0730: out.println("\\\">\\n\");");
0731: }
0732: }
0733:
0734: /*
0735: * Generates the constructor. (shared by servlet and tag handler preamble
0736: * generation)
0737: */
0738: private void generateConstructor(String className) {
0739: out.printil("public " + className + "() {");
0740: out.printil("}");
0741: out.println();
0742: }
0743:
0744: /**
0745: * A visitor that generates codes for the elements in the page.
0746: */
0747: class GenerateVisitor extends Node.Visitor {
0748:
0749: /*
0750: * Hashtable containing introspection information on tag handlers:
0751: * <key>: tag prefix <value>: hashtable containing introspection on tag
0752: * handlers: <key>: tag short name <value>: introspection info of tag
0753: * handler for <prefix:shortName> tag
0754: */
0755: private Hashtable handlerInfos;
0756:
0757: private Hashtable tagVarNumbers;
0758:
0759: private String parent;
0760:
0761: private boolean isSimpleTagParent; // Is parent a SimpleTag?
0762:
0763: private String pushBodyCountVar;
0764:
0765: private String simpleTagHandlerVar;
0766:
0767: private boolean isSimpleTagHandler;
0768:
0769: private boolean isFragment;
0770:
0771: private boolean isTagFile;
0772:
0773: private ServletWriter out;
0774:
0775: private ArrayList methodsBuffered;
0776:
0777: private FragmentHelperClass fragmentHelperClass;
0778:
0779: private int methodNesting;
0780:
0781: private TagInfo tagInfo;
0782:
0783: private ClassLoader loader;
0784:
0785: private int charArrayCount;
0786:
0787: private HashMap textMap;
0788:
0789: /**
0790: * Constructor.
0791: */
0792: public GenerateVisitor(boolean isTagFile, ServletWriter out,
0793: ArrayList methodsBuffered,
0794: FragmentHelperClass fragmentHelperClass,
0795: ClassLoader loader, TagInfo tagInfo) {
0796:
0797: this .isTagFile = isTagFile;
0798: this .out = out;
0799: this .methodsBuffered = methodsBuffered;
0800: this .fragmentHelperClass = fragmentHelperClass;
0801: this .loader = loader;
0802: this .tagInfo = tagInfo;
0803: methodNesting = 0;
0804: handlerInfos = new Hashtable();
0805: tagVarNumbers = new Hashtable();
0806: textMap = new HashMap();
0807: }
0808:
0809: /**
0810: * Returns an attribute value, optionally URL encoded. If the value is a
0811: * runtime expression, the result is the expression itself, as a string.
0812: * If the result is an EL expression, we insert a call to the
0813: * interpreter. If the result is a Named Attribute we insert the
0814: * generated variable name. Otherwise the result is a string literal,
0815: * quoted and escaped.
0816: *
0817: * @param attr
0818: * An JspAttribute object
0819: * @param encode
0820: * true if to be URL encoded
0821: * @param expectedType
0822: * the expected type for an EL evaluation (ignored for
0823: * attributes that aren't EL expressions)
0824: */
0825: private String attributeValue(Node.JspAttribute attr,
0826: boolean encode, Class expectedType) {
0827: String v = attr.getValue();
0828: if (!attr.isNamedAttribute() && (v == null))
0829: return "";
0830:
0831: if (attr.isExpression()) {
0832: if (encode) {
0833: return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode(String.valueOf("
0834: + v + "), request.getCharacterEncoding())";
0835: }
0836: return v;
0837: } else if (attr.isELInterpreterInput()) {
0838: boolean replaceESC = v.indexOf(Constants.ESC) > 0;
0839: v = JspUtil.interpreterCall(this .isTagFile, v,
0840: expectedType, attr.getEL().getMapName(), false);
0841: // XXX ESC replacement hack
0842: if (replaceESC) {
0843: v = "(" + v + ").replace(" + Constants.ESCStr
0844: + ", '$')";
0845: }
0846: if (encode) {
0847: return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("
0848: + v + ", request.getCharacterEncoding())";
0849: }
0850: return v;
0851: } else if (attr.isNamedAttribute()) {
0852: return attr.getNamedAttributeNode()
0853: .getTemporaryVariableName();
0854: } else {
0855: if (encode) {
0856: return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("
0857: + quote(v)
0858: + ", request.getCharacterEncoding())";
0859: }
0860: return quote(v);
0861: }
0862: }
0863:
0864: /**
0865: * Prints the attribute value specified in the param action, in the form
0866: * of name=value string.
0867: *
0868: * @param n
0869: * the parent node for the param action nodes.
0870: */
0871: private void printParams(Node n, String pageParam,
0872: boolean literal) throws JasperException {
0873:
0874: class ParamVisitor extends Node.Visitor {
0875: String separator;
0876:
0877: ParamVisitor(String separator) {
0878: this .separator = separator;
0879: }
0880:
0881: public void visit(Node.ParamAction n)
0882: throws JasperException {
0883:
0884: out.print(" + ");
0885: out.print(separator);
0886: out.print(" + ");
0887: out
0888: .print("org.apache.jasper.runtime.JspRuntimeLibrary."
0889: + "URLEncode("
0890: + quote(n.getTextAttribute("name"))
0891: + ", request.getCharacterEncoding())");
0892: out.print("+ \"=\" + ");
0893: out.print(attributeValue(n.getValue(), true,
0894: String.class));
0895:
0896: // The separator is '&' after the second use
0897: separator = "\"&\"";
0898: }
0899: }
0900:
0901: String sep;
0902: if (literal) {
0903: sep = pageParam.indexOf('?') > 0 ? "\"&\"" : "\"?\"";
0904: } else {
0905: sep = "((" + pageParam + ").indexOf('?')>0? '&': '?')";
0906: }
0907: if (n.getBody() != null) {
0908: n.getBody().visit(new ParamVisitor(sep));
0909: }
0910: }
0911:
0912: public void visit(Node.Expression n) throws JasperException {
0913: n.setBeginJavaLine(out.getJavaLine());
0914: out.printin("out.print(");
0915: out.printMultiLn(n.getText());
0916: out.println(");");
0917: n.setEndJavaLine(out.getJavaLine());
0918: }
0919:
0920: public void visit(Node.Scriptlet n) throws JasperException {
0921: n.setBeginJavaLine(out.getJavaLine());
0922: out.printMultiLn(n.getText());
0923: out.println();
0924: n.setEndJavaLine(out.getJavaLine());
0925: }
0926:
0927: public void visit(Node.ELExpression n) throws JasperException {
0928: n.setBeginJavaLine(out.getJavaLine());
0929: if (!pageInfo.isELIgnored() && (n.getEL() != null)) {
0930: out.printil("out.write("
0931: + JspUtil.interpreterCall(this .isTagFile, n
0932: .getType()
0933: + "{" + new String(n.getText()) + "}",
0934: String.class, n.getEL().getMapName(),
0935: false) + ");");
0936: } else {
0937: out
0938: .printil("out.write("
0939: + quote(n.getType() + "{"
0940: + new String(n.getText()) + "}")
0941: + ");");
0942: }
0943: n.setEndJavaLine(out.getJavaLine());
0944: }
0945:
0946: public void visit(Node.IncludeAction n) throws JasperException {
0947:
0948: String flush = n.getTextAttribute("flush");
0949: Node.JspAttribute page = n.getPage();
0950:
0951: boolean isFlush = false; // default to false;
0952: if ("true".equals(flush))
0953: isFlush = true;
0954:
0955: n.setBeginJavaLine(out.getJavaLine());
0956:
0957: String pageParam;
0958: if (page.isNamedAttribute()) {
0959: // If the page for jsp:include was specified via
0960: // jsp:attribute, first generate code to evaluate
0961: // that body.
0962: pageParam = generateNamedAttributeValue(page
0963: .getNamedAttributeNode());
0964: } else {
0965: pageParam = attributeValue(page, false, String.class);
0966: }
0967:
0968: // If any of the params have their values specified by
0969: // jsp:attribute, prepare those values first.
0970: Node jspBody = findJspBody(n);
0971: if (jspBody != null) {
0972: prepareParams(jspBody);
0973: } else {
0974: prepareParams(n);
0975: }
0976:
0977: out
0978: .printin("org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "
0979: + pageParam);
0980: printParams(n, pageParam, page.isLiteral());
0981: out.println(", out, " + isFlush + ");");
0982:
0983: n.setEndJavaLine(out.getJavaLine());
0984: }
0985:
0986: /**
0987: * Scans through all child nodes of the given parent for <param>
0988: * subelements. For each <param> element, if its value is specified via
0989: * a Named Attribute (<jsp:attribute>), generate the code to evaluate
0990: * those bodies first.
0991: * <p>
0992: * If parent is null, simply returns.
0993: */
0994: private void prepareParams(Node parent) throws JasperException {
0995: if (parent == null)
0996: return;
0997:
0998: Node.Nodes subelements = parent.getBody();
0999: if (subelements != null) {
1000: for (int i = 0; i < subelements.size(); i++) {
1001: Node n = subelements.getNode(i);
1002: if (n instanceof Node.ParamAction) {
1003: Node.Nodes paramSubElements = n.getBody();
1004: for (int j = 0; (paramSubElements != null)
1005: && (j < paramSubElements.size()); j++) {
1006: Node m = paramSubElements.getNode(j);
1007: if (m instanceof Node.NamedAttribute) {
1008: generateNamedAttributeValue((Node.NamedAttribute) m);
1009: }
1010: }
1011: }
1012: }
1013: }
1014: }
1015:
1016: /**
1017: * Finds the <jsp:body> subelement of the given parent node. If not
1018: * found, null is returned.
1019: */
1020: private Node.JspBody findJspBody(Node parent)
1021: throws JasperException {
1022: Node.JspBody result = null;
1023:
1024: Node.Nodes subelements = parent.getBody();
1025: for (int i = 0; (subelements != null)
1026: && (i < subelements.size()); i++) {
1027: Node n = subelements.getNode(i);
1028: if (n instanceof Node.JspBody) {
1029: result = (Node.JspBody) n;
1030: break;
1031: }
1032: }
1033:
1034: return result;
1035: }
1036:
1037: public void visit(Node.ForwardAction n) throws JasperException {
1038: Node.JspAttribute page = n.getPage();
1039:
1040: n.setBeginJavaLine(out.getJavaLine());
1041:
1042: out.printil("if (true) {"); // So that javac won't complain about
1043: out.pushIndent(); // codes after "return"
1044:
1045: String pageParam;
1046: if (page.isNamedAttribute()) {
1047: // If the page for jsp:forward was specified via
1048: // jsp:attribute, first generate code to evaluate
1049: // that body.
1050: pageParam = generateNamedAttributeValue(page
1051: .getNamedAttributeNode());
1052: } else {
1053: pageParam = attributeValue(page, false, String.class);
1054: }
1055:
1056: // If any of the params have their values specified by
1057: // jsp:attribute, prepare those values first.
1058: Node jspBody = findJspBody(n);
1059: if (jspBody != null) {
1060: prepareParams(jspBody);
1061: } else {
1062: prepareParams(n);
1063: }
1064:
1065: out.printin("_jspx_page_context.forward(");
1066: out.print(pageParam);
1067: printParams(n, pageParam, page.isLiteral());
1068: out.println(");");
1069: if (isTagFile || isFragment) {
1070: out.printil("throw new SkipPageException();");
1071: } else {
1072: out.printil((methodNesting > 0) ? "return true;"
1073: : "return;");
1074: }
1075: out.popIndent();
1076: out.printil("}");
1077:
1078: n.setEndJavaLine(out.getJavaLine());
1079: // XXX Not sure if we can eliminate dead codes after this.
1080: }
1081:
1082: public void visit(Node.GetProperty n) throws JasperException {
1083: String name = n.getTextAttribute("name");
1084: String property = n.getTextAttribute("property");
1085:
1086: n.setBeginJavaLine(out.getJavaLine());
1087:
1088: if (beanInfo.checkVariable(name)) {
1089: // Bean is defined using useBean, introspect at compile time
1090: Class bean = beanInfo.getBeanType(name);
1091: String beanName = JspUtil.getCanonicalName(bean);
1092: java.lang.reflect.Method meth = JspRuntimeLibrary
1093: .getReadMethod(bean, property);
1094: String methodName = meth.getName();
1095: out
1096: .printil("out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString("
1097: + "((("
1098: + beanName
1099: + ")_jspx_page_context.findAttribute("
1100: + "\""
1101: + name
1102: + "\"))."
1103: + methodName
1104: + "())));");
1105: } else {
1106: // The object could be a custom action with an associated
1107: // VariableInfo entry for this name.
1108: // Get the class name and then introspect at runtime.
1109: out
1110: .printil("out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString"
1111: + "(org.apache.jasper.runtime.JspRuntimeLibrary.handleGetProperty"
1112: + "(_jspx_page_context.getAttribute(\""
1113: + name
1114: + "\", PageContext.PAGE_SCOPE), \""
1115: + property + "\")));");
1116: }
1117:
1118: n.setEndJavaLine(out.getJavaLine());
1119: }
1120:
1121: public void visit(Node.SetProperty n) throws JasperException {
1122: String name = n.getTextAttribute("name");
1123: String property = n.getTextAttribute("property");
1124: String param = n.getTextAttribute("param");
1125: Node.JspAttribute value = n.getValue();
1126:
1127: n.setBeginJavaLine(out.getJavaLine());
1128:
1129: if ("*".equals(property)) {
1130: out
1131: .printil("org.apache.jasper.runtime.JspRuntimeLibrary.introspect("
1132: + "_jspx_page_context.findAttribute("
1133: + "\"" + name + "\"), request);");
1134: } else if (value == null) {
1135: if (param == null)
1136: param = property; // default to same as property
1137: out
1138: .printil("org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper("
1139: + "_jspx_page_context.findAttribute(\""
1140: + name
1141: + "\"), \""
1142: + property
1143: + "\", request.getParameter(\""
1144: + param
1145: + "\"), "
1146: + "request, \""
1147: + param
1148: + "\", false);");
1149: } else if (value.isExpression()) {
1150: out
1151: .printil("org.apache.jasper.runtime.JspRuntimeLibrary.handleSetProperty("
1152: + "_jspx_page_context.findAttribute(\""
1153: + name + "\"), \"" + property + "\",");
1154: out.print(attributeValue(value, false, null));
1155: out.println(");");
1156: } else if (value.isELInterpreterInput()) {
1157: // We've got to resolve the very call to the interpreter
1158: // at runtime since we don't know what type to expect
1159: // in the general case; we thus can't hard-wire the call
1160: // into the generated code. (XXX We could, however,
1161: // optimize the case where the bean is exposed with
1162: // <jsp:useBean>, much as the code here does for
1163: // getProperty.)
1164:
1165: // The following holds true for the arguments passed to
1166: // JspRuntimeLibrary.handleSetPropertyExpression():
1167: // - 'pageContext' is a VariableResolver.
1168: // - 'this' (either the generated Servlet or the generated tag
1169: // handler for Tag files) is a FunctionMapper.
1170: out
1171: .printil("org.apache.jasper.runtime.JspRuntimeLibrary.handleSetPropertyExpression("
1172: + "_jspx_page_context.findAttribute(\""
1173: + name
1174: + "\"), \""
1175: + property
1176: + "\", "
1177: + quote(value.getValue())
1178: + ", "
1179: + "_jspx_page_context, "
1180: + value.getEL().getMapName() + ");");
1181: } else if (value.isNamedAttribute()) {
1182: // If the value for setProperty was specified via
1183: // jsp:attribute, first generate code to evaluate
1184: // that body.
1185: String valueVarName = generateNamedAttributeValue(value
1186: .getNamedAttributeNode());
1187: out
1188: .printil("org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper("
1189: + "_jspx_page_context.findAttribute(\""
1190: + name
1191: + "\"), \""
1192: + property
1193: + "\", "
1194: + valueVarName
1195: + ", null, null, false);");
1196: } else {
1197: out
1198: .printin("org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper("
1199: + "_jspx_page_context.findAttribute(\""
1200: + name + "\"), \"" + property + "\", ");
1201: out.print(attributeValue(value, false, null));
1202: out.println(", null, null, false);");
1203: }
1204:
1205: n.setEndJavaLine(out.getJavaLine());
1206: }
1207:
1208: public void visit(Node.UseBean n) throws JasperException {
1209:
1210: String name = n.getTextAttribute("id");
1211: String scope = n.getTextAttribute("scope");
1212: String klass = n.getTextAttribute("class");
1213: String type = n.getTextAttribute("type");
1214: Node.JspAttribute beanName = n.getBeanName();
1215:
1216: // If "class" is specified, try an instantiation at compile time
1217: boolean generateNew = false;
1218: String canonicalName = null; // Canonical name for klass
1219: if (klass != null) {
1220: try {
1221: Class bean = ctxt.getClassLoader().loadClass(klass);
1222: if (klass.indexOf('$') >= 0) {
1223: // Obtain the canonical type name
1224: canonicalName = JspUtil.getCanonicalName(bean);
1225: } else {
1226: canonicalName = klass;
1227: }
1228: int modifiers = bean.getModifiers();
1229: if (!Modifier.isPublic(modifiers)
1230: || Modifier.isInterface(modifiers)
1231: || Modifier.isAbstract(modifiers)) {
1232: throw new Exception(
1233: "Invalid bean class modifier");
1234: }
1235: // Check that there is a 0 arg constructor
1236: bean.getConstructor(new Class[] {});
1237: // At compile time, we have determined that the bean class
1238: // exists, with a public zero constructor, new() can be
1239: // used for bean instantiation.
1240: generateNew = true;
1241: } catch (Exception e) {
1242: // Cannot instantiate the specified class, either a
1243: // compilation error or a runtime error will be raised,
1244: // depending on a compiler flag.
1245: if (ctxt.getOptions()
1246: .getErrorOnUseBeanInvalidClassAttribute()) {
1247: err
1248: .jspError(n, "jsp.error.invalid.bean",
1249: klass);
1250: }
1251: if (canonicalName == null) {
1252: // Doing our best here to get a canonical name
1253: // from the binary name, should work 99.99% of time.
1254: canonicalName = klass.replace('$', '.');
1255: }
1256: }
1257: if (type == null) {
1258: // if type is unspecified, use "class" as type of bean
1259: type = canonicalName;
1260: }
1261: }
1262:
1263: String scopename = "PageContext.PAGE_SCOPE"; // Default to page
1264: String lock = "_jspx_page_context";
1265:
1266: if ("request".equals(scope)) {
1267: scopename = "PageContext.REQUEST_SCOPE";
1268: lock = "request";
1269: } else if ("session".equals(scope)) {
1270: scopename = "PageContext.SESSION_SCOPE";
1271: lock = "session";
1272: } else if ("application".equals(scope)) {
1273: scopename = "PageContext.APPLICATION_SCOPE";
1274: lock = "application";
1275: }
1276:
1277: n.setBeginJavaLine(out.getJavaLine());
1278:
1279: // Declare bean
1280: out.printin(type);
1281: out.print(' ');
1282: out.print(name);
1283: out.println(" = null;");
1284:
1285: // Lock while getting or creating bean
1286: out.printin("synchronized (");
1287: out.print(lock);
1288: out.println(") {");
1289: out.pushIndent();
1290:
1291: // Locate bean from context
1292: out.printin(name);
1293: out.print(" = (");
1294: out.print(type);
1295: out.print(") _jspx_page_context.getAttribute(");
1296: out.print(quote(name));
1297: out.print(", ");
1298: out.print(scopename);
1299: out.println(");");
1300:
1301: // Create bean
1302: /*
1303: * Check if bean is alredy there
1304: */
1305: out.printin("if (");
1306: out.print(name);
1307: out.println(" == null){");
1308: out.pushIndent();
1309: if (klass == null && beanName == null) {
1310: /*
1311: * If both class name and beanName is not specified, the bean
1312: * must be found locally, otherwise it's an error
1313: */
1314: out
1315: .printin("throw new java.lang.InstantiationException(\"bean ");
1316: out.print(name);
1317: out.println(" not found within scope\");");
1318: } else {
1319: /*
1320: * Instantiate the bean if it is not in the specified scope.
1321: */
1322: if (!generateNew) {
1323: String binaryName;
1324: if (beanName != null) {
1325: if (beanName.isNamedAttribute()) {
1326: // If the value for beanName was specified via
1327: // jsp:attribute, first generate code to evaluate
1328: // that body.
1329: binaryName = generateNamedAttributeValue(beanName
1330: .getNamedAttributeNode());
1331: } else {
1332: binaryName = attributeValue(beanName,
1333: false, String.class);
1334: }
1335: } else {
1336: // Implies klass is not null
1337: binaryName = quote(klass);
1338: }
1339: out.printil("try {");
1340: out.pushIndent();
1341: out.printin(name);
1342: out.print(" = (");
1343: out.print(type);
1344: out.print(") java.beans.Beans.instantiate(");
1345: out.print("this.getClass().getClassLoader(), ");
1346: out.print(binaryName);
1347: out.println(");");
1348: out.popIndent();
1349: /*
1350: * Note: Beans.instantiate throws ClassNotFoundException if
1351: * the bean class is abstract.
1352: */
1353: out
1354: .printil("} catch (ClassNotFoundException exc) {");
1355: out.pushIndent();
1356: out
1357: .printil("throw new InstantiationException(exc.getMessage());");
1358: out.popIndent();
1359: out.printil("} catch (Exception exc) {");
1360: out.pushIndent();
1361: out.printin("throw new ServletException(");
1362: out.print("\"Cannot create bean of class \" + ");
1363: out.print(binaryName);
1364: out.println(", exc);");
1365: out.popIndent();
1366: out.printil("}"); // close of try
1367: } else {
1368: // Implies klass is not null
1369: // Generate codes to instantiate the bean class
1370: out.printin(name);
1371: out.print(" = new ");
1372: out.print(canonicalName);
1373: out.println("();");
1374: }
1375: /*
1376: * Set attribute for bean in the specified scope
1377: */
1378: out.printin("_jspx_page_context.setAttribute(");
1379: out.print(quote(name));
1380: out.print(", ");
1381: out.print(name);
1382: out.print(", ");
1383: out.print(scopename);
1384: out.println(");");
1385:
1386: // Only visit the body when bean is instantiated
1387: visitBody(n);
1388: }
1389: out.popIndent();
1390: out.printil("}");
1391:
1392: // End of lock block
1393: out.popIndent();
1394: out.printil("}");
1395:
1396: n.setEndJavaLine(out.getJavaLine());
1397: }
1398:
1399: /**
1400: * @return a string for the form 'attr = "value"'
1401: */
1402: private String makeAttr(String attr, String value) {
1403: if (value == null)
1404: return "";
1405:
1406: return " " + attr + "=\"" + value + '\"';
1407: }
1408:
1409: public void visit(Node.PlugIn n) throws JasperException {
1410:
1411: /**
1412: * A visitor to handle <jsp:param> in a plugin
1413: */
1414: class ParamVisitor extends Node.Visitor {
1415:
1416: private boolean ie;
1417:
1418: ParamVisitor(boolean ie) {
1419: this .ie = ie;
1420: }
1421:
1422: public void visit(Node.ParamAction n)
1423: throws JasperException {
1424:
1425: String name = n.getTextAttribute("name");
1426: if (name.equalsIgnoreCase("object"))
1427: name = "java_object";
1428: else if (name.equalsIgnoreCase("type"))
1429: name = "java_type";
1430:
1431: n.setBeginJavaLine(out.getJavaLine());
1432: // XXX - Fixed a bug here - value used to be output
1433: // inline, which is only okay if value is not an EL
1434: // expression. Also, key/value pairs for the
1435: // embed tag were not being generated correctly.
1436: // Double check that this is now the correct behavior.
1437: if (ie) {
1438: // We want something of the form
1439: // out.println( "<param name=\"blah\"
1440: // value=\"" + ... + "\">" );
1441: out.printil("out.write( \"<param name=\\\""
1442: + escape(name)
1443: + "\\\" value=\\\"\" + "
1444: + attributeValue(n.getValue(), false,
1445: String.class)
1446: + " + \"\\\">\" );");
1447: out.printil("out.write(\"\\n\");");
1448: } else {
1449: // We want something of the form
1450: // out.print( " blah=\"" + ... + "\"" );
1451: out.printil("out.write( \" "
1452: + escape(name)
1453: + "=\\\"\" + "
1454: + attributeValue(n.getValue(), false,
1455: String.class)
1456: + " + \"\\\"\" );");
1457: }
1458:
1459: n.setEndJavaLine(out.getJavaLine());
1460: }
1461: }
1462:
1463: String type = n.getTextAttribute("type");
1464: String code = n.getTextAttribute("code");
1465: String name = n.getTextAttribute("name");
1466: Node.JspAttribute height = n.getHeight();
1467: Node.JspAttribute width = n.getWidth();
1468: String hspace = n.getTextAttribute("hspace");
1469: String vspace = n.getTextAttribute("vspace");
1470: String align = n.getTextAttribute("align");
1471: String iepluginurl = n.getTextAttribute("iepluginurl");
1472: String nspluginurl = n.getTextAttribute("nspluginurl");
1473: String codebase = n.getTextAttribute("codebase");
1474: String archive = n.getTextAttribute("archive");
1475: String jreversion = n.getTextAttribute("jreversion");
1476:
1477: String widthStr = null;
1478: if (width != null) {
1479: if (width.isNamedAttribute()) {
1480: widthStr = generateNamedAttributeValue(width
1481: .getNamedAttributeNode());
1482: } else {
1483: widthStr = attributeValue(width, false,
1484: String.class);
1485: }
1486: }
1487:
1488: String heightStr = null;
1489: if (height != null) {
1490: if (height.isNamedAttribute()) {
1491: heightStr = generateNamedAttributeValue(height
1492: .getNamedAttributeNode());
1493: } else {
1494: heightStr = attributeValue(height, false,
1495: String.class);
1496: }
1497: }
1498:
1499: if (iepluginurl == null)
1500: iepluginurl = Constants.IE_PLUGIN_URL;
1501: if (nspluginurl == null)
1502: nspluginurl = Constants.NS_PLUGIN_URL;
1503:
1504: n.setBeginJavaLine(out.getJavaLine());
1505:
1506: // If any of the params have their values specified by
1507: // jsp:attribute, prepare those values first.
1508: // Look for a params node and prepare its param subelements:
1509: Node.JspBody jspBody = findJspBody(n);
1510: if (jspBody != null) {
1511: Node.Nodes subelements = jspBody.getBody();
1512: if (subelements != null) {
1513: for (int i = 0; i < subelements.size(); i++) {
1514: Node m = subelements.getNode(i);
1515: if (m instanceof Node.ParamsAction) {
1516: prepareParams(m);
1517: break;
1518: }
1519: }
1520: }
1521: }
1522:
1523: // XXX - Fixed a bug here - width and height can be set
1524: // dynamically. Double-check if this generation is correct.
1525:
1526: // IE style plugin
1527: // <object ...>
1528: // First compose the runtime output string
1529: String s0 = "<object"
1530: + makeAttr("classid", ctxt.getOptions()
1531: .getIeClassId()) + makeAttr("name", name);
1532:
1533: String s1 = "";
1534: if (width != null) {
1535: s1 = " + \" width=\\\"\" + " + widthStr + " + \"\\\"\"";
1536: }
1537:
1538: String s2 = "";
1539: if (height != null) {
1540: s2 = " + \" height=\\\"\" + " + heightStr
1541: + " + \"\\\"\"";
1542: }
1543:
1544: String s3 = makeAttr("hspace", hspace)
1545: + makeAttr("vspace", vspace)
1546: + makeAttr("align", align)
1547: + makeAttr("codebase", iepluginurl) + '>';
1548:
1549: // Then print the output string to the java file
1550: out.printil("out.write(" + quote(s0) + s1 + s2 + " + "
1551: + quote(s3) + ");");
1552: out.printil("out.write(\"\\n\");");
1553:
1554: // <param > for java_code
1555: s0 = "<param name=\"java_code\"" + makeAttr("value", code)
1556: + '>';
1557: out.printil("out.write(" + quote(s0) + ");");
1558: out.printil("out.write(\"\\n\");");
1559:
1560: // <param > for java_codebase
1561: if (codebase != null) {
1562: s0 = "<param name=\"java_codebase\""
1563: + makeAttr("value", codebase) + '>';
1564: out.printil("out.write(" + quote(s0) + ");");
1565: out.printil("out.write(\"\\n\");");
1566: }
1567:
1568: // <param > for java_archive
1569: if (archive != null) {
1570: s0 = "<param name=\"java_archive\""
1571: + makeAttr("value", archive) + '>';
1572: out.printil("out.write(" + quote(s0) + ");");
1573: out.printil("out.write(\"\\n\");");
1574: }
1575:
1576: // <param > for type
1577: s0 = "<param name=\"type\""
1578: + makeAttr("value", "application/x-java-"
1579: + type
1580: + ";"
1581: + ((jreversion == null) ? "" : "version="
1582: + jreversion)) + '>';
1583: out.printil("out.write(" + quote(s0) + ");");
1584: out.printil("out.write(\"\\n\");");
1585:
1586: /*
1587: * generate a <param> for each <jsp:param> in the plugin body
1588: */
1589: if (n.getBody() != null)
1590: n.getBody().visit(new ParamVisitor(true));
1591:
1592: /*
1593: * Netscape style plugin part
1594: */
1595: out.printil("out.write(" + quote("<comment>") + ");");
1596: out.printil("out.write(\"\\n\");");
1597: s0 = "<EMBED"
1598: + makeAttr("type", "application/x-java-"
1599: + type
1600: + ";"
1601: + ((jreversion == null) ? "" : "version="
1602: + jreversion))
1603: + makeAttr("name", name);
1604:
1605: // s1 and s2 are the same as before.
1606:
1607: s3 = makeAttr("hspace", hspace)
1608: + makeAttr("vspace", vspace)
1609: + makeAttr("align", align)
1610: + makeAttr("pluginspage", nspluginurl)
1611: + makeAttr("java_code", code)
1612: + makeAttr("java_codebase", codebase)
1613: + makeAttr("java_archive", archive);
1614: out.printil("out.write(" + quote(s0) + s1 + s2 + " + "
1615: + quote(s3) + ");");
1616:
1617: /*
1618: * Generate a 'attr = "value"' for each <jsp:param> in plugin body
1619: */
1620: if (n.getBody() != null)
1621: n.getBody().visit(new ParamVisitor(false));
1622:
1623: out.printil("out.write(" + quote("/>") + ");");
1624: out.printil("out.write(\"\\n\");");
1625:
1626: out.printil("out.write(" + quote("<noembed>") + ");");
1627: out.printil("out.write(\"\\n\");");
1628:
1629: /*
1630: * Fallback
1631: */
1632: if (n.getBody() != null) {
1633: visitBody(n);
1634: out.printil("out.write(\"\\n\");");
1635: }
1636:
1637: out.printil("out.write(" + quote("</noembed>") + ");");
1638: out.printil("out.write(\"\\n\");");
1639:
1640: out.printil("out.write(" + quote("</comment>") + ");");
1641: out.printil("out.write(\"\\n\");");
1642:
1643: out.printil("out.write(" + quote("</object>") + ");");
1644: out.printil("out.write(\"\\n\");");
1645:
1646: n.setEndJavaLine(out.getJavaLine());
1647: }
1648:
1649: public void visit(Node.NamedAttribute n) throws JasperException {
1650: // Don't visit body of this tag - we already did earlier.
1651: }
1652:
1653: public void visit(Node.CustomTag n) throws JasperException {
1654:
1655: // Use plugin to generate more efficient code if there is one.
1656: if (n.useTagPlugin()) {
1657: generateTagPlugin(n);
1658: return;
1659: }
1660:
1661: TagHandlerInfo handlerInfo = getTagHandlerInfo(n);
1662:
1663: // Create variable names
1664: String baseVar = createTagVarName(n.getQName(), n
1665: .getPrefix(), n.getLocalName());
1666: String tagEvalVar = "_jspx_eval_" + baseVar;
1667: String tagHandlerVar = "_jspx_th_" + baseVar;
1668: String tagPushBodyCountVar = "_jspx_push_body_count_"
1669: + baseVar;
1670:
1671: // If the tag contains no scripting element, generate its codes
1672: // to a method.
1673: ServletWriter outSave = null;
1674: Node.ChildInfo ci = n.getChildInfo();
1675: if (ci.isScriptless() && !ci.hasScriptingVars()) {
1676: // The tag handler and its body code can reside in a separate
1677: // method if it is scriptless and does not have any scripting
1678: // variable defined.
1679:
1680: String tagMethod = "_jspx_meth_" + baseVar;
1681:
1682: // Generate a call to this method
1683: out.printin("if (");
1684: out.print(tagMethod);
1685: out.print("(");
1686: if (parent != null) {
1687: out.print(parent);
1688: out.print(", ");
1689: }
1690: out.print("_jspx_page_context");
1691: if (pushBodyCountVar != null) {
1692: out.print(", ");
1693: out.print(pushBodyCountVar);
1694: }
1695: out.println("))");
1696: out.pushIndent();
1697: out.printil((methodNesting > 0) ? "return true;"
1698: : "return;");
1699: out.popIndent();
1700:
1701: // Set up new buffer for the method
1702: outSave = out;
1703: /*
1704: * For fragments, their bodies will be generated in fragment
1705: * helper classes, and the Java line adjustments will be done
1706: * there, hence they are set to null here to avoid double
1707: * adjustments.
1708: */
1709: GenBuffer genBuffer = new GenBuffer(n, n
1710: .implements SimpleTag() ? null : n.getBody());
1711: methodsBuffered.add(genBuffer);
1712: out = genBuffer.getOut();
1713:
1714: methodNesting++;
1715: // Generate code for method declaration
1716: out.println();
1717: out.pushIndent();
1718: out.printin("private boolean ");
1719: out.print(tagMethod);
1720: out.print("(");
1721: if (parent != null) {
1722: out.print("javax.servlet.jsp.tagext.JspTag ");
1723: out.print(parent);
1724: out.print(", ");
1725: }
1726: out.print("PageContext _jspx_page_context");
1727: if (pushBodyCountVar != null) {
1728: out.print(", int[] ");
1729: out.print(pushBodyCountVar);
1730: }
1731: out.println(")");
1732: out.printil(" throws Throwable {");
1733: out.pushIndent();
1734:
1735: // Initilaize local variables used in this method.
1736: if (!isTagFile) {
1737: out
1738: .printil("PageContext pageContext = _jspx_page_context;");
1739: }
1740: out
1741: .printil("JspWriter out = _jspx_page_context.getOut();");
1742: generateLocalVariables(out, n);
1743: }
1744:
1745: if (n.implements SimpleTag()) {
1746: generateCustomDoTag(n, handlerInfo, tagHandlerVar);
1747: } else {
1748: /*
1749: * Classic tag handler: Generate code for start element, body,
1750: * and end element
1751: */
1752: generateCustomStart(n, handlerInfo, tagHandlerVar,
1753: tagEvalVar, tagPushBodyCountVar);
1754:
1755: // visit body
1756: String tmpParent = parent;
1757: parent = tagHandlerVar;
1758: boolean isSimpleTagParentSave = isSimpleTagParent;
1759: isSimpleTagParent = false;
1760: String tmpPushBodyCountVar = null;
1761: if (n.implements TryCatchFinally()) {
1762: tmpPushBodyCountVar = pushBodyCountVar;
1763: pushBodyCountVar = tagPushBodyCountVar;
1764: }
1765: boolean tmpIsSimpleTagHandler = isSimpleTagHandler;
1766: isSimpleTagHandler = false;
1767:
1768: visitBody(n);
1769:
1770: parent = tmpParent;
1771: isSimpleTagParent = isSimpleTagParentSave;
1772: if (n.implements TryCatchFinally()) {
1773: pushBodyCountVar = tmpPushBodyCountVar;
1774: }
1775: isSimpleTagHandler = tmpIsSimpleTagHandler;
1776:
1777: generateCustomEnd(n, tagHandlerVar, tagEvalVar,
1778: tagPushBodyCountVar);
1779: }
1780:
1781: if (ci.isScriptless() && !ci.hasScriptingVars()) {
1782: // Generate end of method
1783: if (methodNesting > 0) {
1784: out.printil("return false;");
1785: }
1786: out.popIndent();
1787: out.printil("}");
1788: out.popIndent();
1789:
1790: methodNesting--;
1791:
1792: // restore previous writer
1793: out = outSave;
1794: }
1795: }
1796:
1797: private static final String SINGLE_QUOTE = "'";
1798:
1799: private static final String DOUBLE_QUOTE = "\\\"";
1800:
1801: public void visit(Node.UninterpretedTag n)
1802: throws JasperException {
1803:
1804: n.setBeginJavaLine(out.getJavaLine());
1805:
1806: /*
1807: * Write begin tag
1808: */
1809: out.printin("out.write(\"<");
1810: out.print(n.getQName());
1811:
1812: Attributes attrs = n.getNonTaglibXmlnsAttributes();
1813: int attrsLen = (attrs == null) ? 0 : attrs.getLength();
1814: for (int i = 0; i < attrsLen; i++) {
1815: out.print(" ");
1816: out.print(attrs.getQName(i));
1817: out.print("=");
1818: String quote = DOUBLE_QUOTE;
1819: String value = attrs.getValue(i);
1820: if (value.indexOf('"') != -1) {
1821: quote = SINGLE_QUOTE;
1822: }
1823: out.print(quote);
1824: out.print(value);
1825: out.print(quote);
1826: }
1827:
1828: attrs = n.getAttributes();
1829: attrsLen = (attrs == null) ? 0 : attrs.getLength();
1830: Node.JspAttribute[] jspAttrs = n.getJspAttributes();
1831: for (int i = 0; i < attrsLen; i++) {
1832: out.print(" ");
1833: out.print(attrs.getQName(i));
1834: out.print("=");
1835: if (jspAttrs[i].isELInterpreterInput()) {
1836: out.print("\\\"\" + ");
1837: out.print(attributeValue(jspAttrs[i], false,
1838: String.class));
1839: out.print(" + \"\\\"");
1840: } else {
1841: String quote = DOUBLE_QUOTE;
1842: String value = attrs.getValue(i);
1843: if (value.indexOf('"') != -1) {
1844: quote = SINGLE_QUOTE;
1845: }
1846: out.print(quote);
1847: out.print(value);
1848: out.print(quote);
1849: }
1850: }
1851:
1852: if (n.getBody() != null) {
1853: out.println(">\");");
1854:
1855: // Visit tag body
1856: visitBody(n);
1857:
1858: /*
1859: * Write end tag
1860: */
1861: out.printin("out.write(\"</");
1862: out.print(n.getQName());
1863: out.println(">\");");
1864: } else {
1865: out.println("/>\");");
1866: }
1867:
1868: n.setEndJavaLine(out.getJavaLine());
1869: }
1870:
1871: public void visit(Node.JspElement n) throws JasperException {
1872:
1873: n.setBeginJavaLine(out.getJavaLine());
1874:
1875: // Compute attribute value string for XML-style and named
1876: // attributes
1877: Hashtable map = new Hashtable();
1878: Node.JspAttribute[] attrs = n.getJspAttributes();
1879: for (int i = 0; attrs != null && i < attrs.length; i++) {
1880: String attrStr = null;
1881: if (attrs[i].isNamedAttribute()) {
1882: attrStr = generateNamedAttributeValue(attrs[i]
1883: .getNamedAttributeNode());
1884: } else {
1885: attrStr = attributeValue(attrs[i], false,
1886: Object.class);
1887: }
1888: String s = " + \" " + attrs[i].getName() + "=\\\"\" + "
1889: + attrStr + " + \"\\\"\"";
1890: map.put(attrs[i].getName(), s);
1891: }
1892:
1893: // Write begin tag, using XML-style 'name' attribute as the
1894: // element name
1895: String elemName = attributeValue(n.getNameAttribute(),
1896: false, String.class);
1897: out.printin("out.write(\"<\"");
1898: out.print(" + " + elemName);
1899:
1900: // Write remaining attributes
1901: Enumeration enumeration = map.keys();
1902: while (enumeration.hasMoreElements()) {
1903: String attrName = (String) enumeration.nextElement();
1904: out.print((String) map.get(attrName));
1905: }
1906:
1907: // Does the <jsp:element> have nested tags other than
1908: // <jsp:attribute>
1909: boolean hasBody = false;
1910: Node.Nodes subelements = n.getBody();
1911: if (subelements != null) {
1912: for (int i = 0; i < subelements.size(); i++) {
1913: Node subelem = subelements.getNode(i);
1914: if (!(subelem instanceof Node.NamedAttribute)) {
1915: hasBody = true;
1916: break;
1917: }
1918: }
1919: }
1920: if (hasBody) {
1921: out.println(" + \">\");");
1922:
1923: // Smap should not include the body
1924: n.setEndJavaLine(out.getJavaLine());
1925:
1926: // Visit tag body
1927: visitBody(n);
1928:
1929: // Write end tag
1930: out.printin("out.write(\"</\"");
1931: out.print(" + " + elemName);
1932: out.println(" + \">\");");
1933: } else {
1934: out.println(" + \"/>\");");
1935: n.setEndJavaLine(out.getJavaLine());
1936: }
1937: }
1938:
1939: public void visit(Node.TemplateText n) throws JasperException {
1940:
1941: String text = n.getText();
1942:
1943: int textSize = text.length();
1944: if (textSize == 0) {
1945: return;
1946: }
1947:
1948: if (textSize <= 3) {
1949: // Special case small text strings
1950: n.setBeginJavaLine(out.getJavaLine());
1951: int lineInc = 0;
1952: for (int i = 0; i < textSize; i++) {
1953: char ch = text.charAt(i);
1954: out.printil("out.write(" + quote(ch) + ");");
1955: if (i > 0) {
1956: n.addSmap(lineInc);
1957: }
1958: if (ch == '\n') {
1959: lineInc++;
1960: }
1961: }
1962: n.setEndJavaLine(out.getJavaLine());
1963: return;
1964: }
1965:
1966: if (ctxt.getOptions().genStringAsCharArray()) {
1967: // Generate Strings as char arrays, for performance
1968: ServletWriter caOut;
1969: if (charArrayBuffer == null) {
1970: charArrayBuffer = new GenBuffer();
1971: caOut = charArrayBuffer.getOut();
1972: caOut.pushIndent();
1973: textMap = new HashMap();
1974: } else {
1975: caOut = charArrayBuffer.getOut();
1976: }
1977: String charArrayName = (String) textMap.get(text);
1978: if (charArrayName == null) {
1979: charArrayName = "_jspx_char_array_"
1980: + charArrayCount++;
1981: textMap.put(text, charArrayName);
1982: caOut.printin("static char[] ");
1983: caOut.print(charArrayName);
1984: caOut.print(" = ");
1985: caOut.print(quote(text));
1986: caOut.println(".toCharArray();");
1987: }
1988:
1989: n.setBeginJavaLine(out.getJavaLine());
1990: out.printil("out.write(" + charArrayName + ");");
1991: n.setEndJavaLine(out.getJavaLine());
1992: return;
1993: }
1994:
1995: n.setBeginJavaLine(out.getJavaLine());
1996:
1997: out.printin();
1998: StringBuffer sb = new StringBuffer("out.write(\"");
1999: int initLength = sb.length();
2000: int count = JspUtil.CHUNKSIZE;
2001: int srcLine = 0; // relative to starting srouce line
2002: for (int i = 0; i < text.length(); i++) {
2003: char ch = text.charAt(i);
2004: --count;
2005: switch (ch) {
2006: case '"':
2007: sb.append('\\').append('\"');
2008: break;
2009: case '\\':
2010: sb.append('\\').append('\\');
2011: break;
2012: case '\r':
2013: sb.append('\\').append('r');
2014: break;
2015: case '\n':
2016: sb.append('\\').append('n');
2017: srcLine++;
2018:
2019: if (breakAtLF || count < 0) {
2020: // Generate an out.write() when see a '\n' in template
2021: sb.append("\");");
2022: out.println(sb.toString());
2023: if (i < text.length() - 1) {
2024: out.printin();
2025: }
2026: sb.setLength(initLength);
2027: count = JspUtil.CHUNKSIZE;
2028: }
2029: // add a Smap for this line
2030: n.addSmap(srcLine);
2031: break;
2032: case '\t': // Not sure we need this
2033: sb.append('\\').append('t');
2034: break;
2035: default:
2036: sb.append(ch);
2037: }
2038: }
2039:
2040: if (sb.length() > initLength) {
2041: sb.append("\");");
2042: out.println(sb.toString());
2043: }
2044:
2045: n.setEndJavaLine(out.getJavaLine());
2046: }
2047:
2048: public void visit(Node.JspBody n) throws JasperException {
2049: if (n.getBody() != null) {
2050: if (isSimpleTagHandler) {
2051: out.printin(simpleTagHandlerVar);
2052: out.print(".setJspBody(");
2053: generateJspFragment(n, simpleTagHandlerVar);
2054: out.println(");");
2055: } else {
2056: visitBody(n);
2057: }
2058: }
2059: }
2060:
2061: public void visit(Node.InvokeAction n) throws JasperException {
2062:
2063: n.setBeginJavaLine(out.getJavaLine());
2064:
2065: // Copy virtual page scope of tag file to page scope of invoking
2066: // page
2067: out
2068: .printil("((org.apache.jasper.runtime.JspContextWrapper) this.jspContext).syncBeforeInvoke();");
2069: String varReaderAttr = n.getTextAttribute("varReader");
2070: String varAttr = n.getTextAttribute("var");
2071: if (varReaderAttr != null || varAttr != null) {
2072: out.printil("_jspx_sout = new java.io.StringWriter();");
2073: } else {
2074: out.printil("_jspx_sout = null;");
2075: }
2076:
2077: // Invoke fragment, unless fragment is null
2078: out.printin("if (");
2079: out.print(toGetterMethod(n.getTextAttribute("fragment")));
2080: out.println(" != null) {");
2081: out.pushIndent();
2082: out.printin(toGetterMethod(n.getTextAttribute("fragment")));
2083: out.println(".invoke(_jspx_sout);");
2084: out.popIndent();
2085: out.printil("}");
2086:
2087: // Store varReader in appropriate scope
2088: if (varReaderAttr != null || varAttr != null) {
2089: String scopeName = n.getTextAttribute("scope");
2090: out.printin("_jspx_page_context.setAttribute(");
2091: if (varReaderAttr != null) {
2092: out.print(quote(varReaderAttr));
2093: out
2094: .print(", new java.io.StringReader(_jspx_sout.toString())");
2095: } else {
2096: out.print(quote(varAttr));
2097: out.print(", _jspx_sout.toString()");
2098: }
2099: if (scopeName != null) {
2100: out.print(", ");
2101: out.print(getScopeConstant(scopeName));
2102: }
2103: out.println(");");
2104: }
2105:
2106: // Restore EL context
2107: out
2108: .printil("jspContext.getELContext().putContext(JspContext.class,getJspContext());");
2109:
2110: n.setEndJavaLine(out.getJavaLine());
2111: }
2112:
2113: public void visit(Node.DoBodyAction n) throws JasperException {
2114:
2115: n.setBeginJavaLine(out.getJavaLine());
2116:
2117: // Copy virtual page scope of tag file to page scope of invoking
2118: // page
2119: out
2120: .printil("((org.apache.jasper.runtime.JspContextWrapper) this.jspContext).syncBeforeInvoke();");
2121:
2122: // Invoke body
2123: String varReaderAttr = n.getTextAttribute("varReader");
2124: String varAttr = n.getTextAttribute("var");
2125: if (varReaderAttr != null || varAttr != null) {
2126: out.printil("_jspx_sout = new java.io.StringWriter();");
2127: } else {
2128: out.printil("_jspx_sout = null;");
2129: }
2130: out.printil("if (getJspBody() != null)");
2131: out.pushIndent();
2132: out.printil("getJspBody().invoke(_jspx_sout);");
2133: out.popIndent();
2134:
2135: // Store varReader in appropriate scope
2136: if (varReaderAttr != null || varAttr != null) {
2137: String scopeName = n.getTextAttribute("scope");
2138: out.printin("_jspx_page_context.setAttribute(");
2139: if (varReaderAttr != null) {
2140: out.print(quote(varReaderAttr));
2141: out
2142: .print(", new java.io.StringReader(_jspx_sout.toString())");
2143: } else {
2144: out.print(quote(varAttr));
2145: out.print(", _jspx_sout.toString()");
2146: }
2147: if (scopeName != null) {
2148: out.print(", ");
2149: out.print(getScopeConstant(scopeName));
2150: }
2151: out.println(");");
2152: }
2153:
2154: // Restore EL context
2155: out
2156: .printil("jspContext.getELContext().putContext(JspContext.class,getJspContext());");
2157:
2158: n.setEndJavaLine(out.getJavaLine());
2159: }
2160:
2161: public void visit(Node.AttributeGenerator n)
2162: throws JasperException {
2163: Node.CustomTag tag = n.getTag();
2164: Node.JspAttribute[] attrs = tag.getJspAttributes();
2165: for (int i = 0; attrs != null && i < attrs.length; i++) {
2166: if (attrs[i].getName().equals(n.getName())) {
2167: out.print(evaluateAttribute(getTagHandlerInfo(tag),
2168: attrs[i], tag, null));
2169: break;
2170: }
2171: }
2172: }
2173:
2174: private TagHandlerInfo getTagHandlerInfo(Node.CustomTag n)
2175: throws JasperException {
2176: Hashtable handlerInfosByShortName = (Hashtable) handlerInfos
2177: .get(n.getPrefix());
2178: if (handlerInfosByShortName == null) {
2179: handlerInfosByShortName = new Hashtable();
2180: handlerInfos
2181: .put(n.getPrefix(), handlerInfosByShortName);
2182: }
2183: TagHandlerInfo handlerInfo = (TagHandlerInfo) handlerInfosByShortName
2184: .get(n.getLocalName());
2185: if (handlerInfo == null) {
2186: handlerInfo = new TagHandlerInfo(n, n
2187: .getTagHandlerClass(), err);
2188: handlerInfosByShortName.put(n.getLocalName(),
2189: handlerInfo);
2190: }
2191: return handlerInfo;
2192: }
2193:
2194: private void generateTagPlugin(Node.CustomTag n)
2195: throws JasperException {
2196: if (n.getAtSTag() != null) {
2197: n.getAtSTag().visit(this );
2198: }
2199: visitBody(n);
2200: if (n.getAtETag() != null) {
2201: n.getAtETag().visit(this );
2202: }
2203: }
2204:
2205: private void generateCustomStart(Node.CustomTag n,
2206: TagHandlerInfo handlerInfo, String tagHandlerVar,
2207: String tagEvalVar, String tagPushBodyCountVar)
2208: throws JasperException {
2209:
2210: Class tagHandlerClass = handlerInfo.getTagHandlerClass();
2211:
2212: out.printin("// ");
2213: out.println(n.getQName());
2214: n.setBeginJavaLine(out.getJavaLine());
2215:
2216: // Declare AT_BEGIN scripting variables
2217: declareScriptingVars(n, VariableInfo.AT_BEGIN);
2218: saveScriptingVars(n, VariableInfo.AT_BEGIN);
2219:
2220: String tagHandlerClassName = JspUtil
2221: .getCanonicalName(tagHandlerClass);
2222: out.printin(tagHandlerClassName);
2223: out.print(" ");
2224: out.print(tagHandlerVar);
2225: out.print(" = ");
2226: if (isPoolingEnabled && !(n.implements JspIdConsumer())) {
2227: out.print("(");
2228: out.print(tagHandlerClassName);
2229: out.print(") ");
2230: out.print(n.getTagHandlerPoolName());
2231: out.print(".get(");
2232: out.print(tagHandlerClassName);
2233: out.println(".class);");
2234: } else {
2235: out.print("new ");
2236: out.print(tagHandlerClassName);
2237: out.println("();");
2238: out
2239: .printin("org.apache.jasper.runtime.AnnotationHelper.postConstruct(");
2240: out.print(VAR_ANNOTATIONPROCESSOR);
2241: out.print(", ");
2242: out.print(tagHandlerVar);
2243: out.println(");");
2244: }
2245:
2246: // includes setting the context
2247: generateSetters(n, tagHandlerVar, handlerInfo, false);
2248:
2249: // JspIdConsumer (after context has been set)
2250: if (n.implements JspIdConsumer()) {
2251: out.printin(tagHandlerVar);
2252: out.print(".setJspId(\"");
2253: out.print(createJspId());
2254: out.println("\");");
2255: }
2256:
2257: if (n.implements TryCatchFinally()) {
2258: out.printin("int[] ");
2259: out.print(tagPushBodyCountVar);
2260: out.println(" = new int[] { 0 };");
2261: out.printil("try {");
2262: out.pushIndent();
2263: }
2264: out.printin("int ");
2265: out.print(tagEvalVar);
2266: out.print(" = ");
2267: out.print(tagHandlerVar);
2268: out.println(".doStartTag();");
2269:
2270: if (!n.implements BodyTag()) {
2271: // Synchronize AT_BEGIN scripting variables
2272: syncScriptingVars(n, VariableInfo.AT_BEGIN);
2273: }
2274:
2275: if (!n.hasEmptyBody()) {
2276: out.printin("if (");
2277: out.print(tagEvalVar);
2278: out
2279: .println(" != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {");
2280: out.pushIndent();
2281:
2282: // Declare NESTED scripting variables
2283: declareScriptingVars(n, VariableInfo.NESTED);
2284: saveScriptingVars(n, VariableInfo.NESTED);
2285:
2286: if (n.implements BodyTag()) {
2287: out.printin("if (");
2288: out.print(tagEvalVar);
2289: out
2290: .println(" != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {");
2291: // Assume EVAL_BODY_BUFFERED
2292: out.pushIndent();
2293: out.printil("out = _jspx_page_context.pushBody();");
2294: if (n.implements TryCatchFinally()) {
2295: out.printin(tagPushBodyCountVar);
2296: out.println("[0]++;");
2297: } else if (pushBodyCountVar != null) {
2298: out.printin(pushBodyCountVar);
2299: out.println("[0]++;");
2300: }
2301: out.printin(tagHandlerVar);
2302: out
2303: .println(".setBodyContent((javax.servlet.jsp.tagext.BodyContent) out);");
2304: out.printin(tagHandlerVar);
2305: out.println(".doInitBody();");
2306:
2307: out.popIndent();
2308: out.printil("}");
2309:
2310: // Synchronize AT_BEGIN and NESTED scripting variables
2311: syncScriptingVars(n, VariableInfo.AT_BEGIN);
2312: syncScriptingVars(n, VariableInfo.NESTED);
2313:
2314: } else {
2315: // Synchronize NESTED scripting variables
2316: syncScriptingVars(n, VariableInfo.NESTED);
2317: }
2318:
2319: if (n.implements IterationTag()) {
2320: out.printil("do {");
2321: out.pushIndent();
2322: }
2323: }
2324: // Map the Java lines that handles start of custom tags to the
2325: // JSP line for this tag
2326: n.setEndJavaLine(out.getJavaLine());
2327: }
2328:
2329: private void generateCustomEnd(Node.CustomTag n,
2330: String tagHandlerVar, String tagEvalVar,
2331: String tagPushBodyCountVar) {
2332:
2333: if (!n.hasEmptyBody()) {
2334: if (n.implements IterationTag()) {
2335: out.printin("int evalDoAfterBody = ");
2336: out.print(tagHandlerVar);
2337: out.println(".doAfterBody();");
2338:
2339: // Synchronize AT_BEGIN and NESTED scripting variables
2340: syncScriptingVars(n, VariableInfo.AT_BEGIN);
2341: syncScriptingVars(n, VariableInfo.NESTED);
2342:
2343: out
2344: .printil("if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)");
2345: out.pushIndent();
2346: out.printil("break;");
2347: out.popIndent();
2348:
2349: out.popIndent();
2350: out.printil("} while (true);");
2351: }
2352:
2353: restoreScriptingVars(n, VariableInfo.NESTED);
2354:
2355: if (n.implements BodyTag()) {
2356: out.printin("if (");
2357: out.print(tagEvalVar);
2358: out
2359: .println(" != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {");
2360: out.pushIndent();
2361: out.printil("out = _jspx_page_context.popBody();");
2362: if (n.implements TryCatchFinally()) {
2363: out.printin(tagPushBodyCountVar);
2364: out.println("[0]--;");
2365: } else if (pushBodyCountVar != null) {
2366: out.printin(pushBodyCountVar);
2367: out.println("[0]--;");
2368: }
2369: out.popIndent();
2370: out.printil("}");
2371: }
2372:
2373: out.popIndent(); // EVAL_BODY
2374: out.printil("}");
2375: }
2376:
2377: out.printin("if (");
2378: out.print(tagHandlerVar);
2379: out
2380: .println(".doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {");
2381: out.pushIndent();
2382: if (!n.implements TryCatchFinally()) {
2383: if (isPoolingEnabled && !(n.implements JspIdConsumer())) {
2384: out.printin(n.getTagHandlerPoolName());
2385: out.print(".reuse(");
2386: out.print(tagHandlerVar);
2387: out.println(");");
2388: } else {
2389: out.printin(tagHandlerVar);
2390: out.println(".release();");
2391: out
2392: .printin("org.apache.jasper.runtime.AnnotationHelper.preDestroy(");
2393: out.print(VAR_ANNOTATIONPROCESSOR);
2394: out.print(", ");
2395: out.print(tagHandlerVar);
2396: out.println(");");
2397: }
2398: }
2399: if (isTagFile || isFragment) {
2400: out.printil("throw new SkipPageException();");
2401: } else {
2402: out.printil((methodNesting > 0) ? "return true;"
2403: : "return;");
2404: }
2405: out.popIndent();
2406: out.printil("}");
2407: // Synchronize AT_BEGIN scripting variables
2408: syncScriptingVars(n, VariableInfo.AT_BEGIN);
2409:
2410: // TryCatchFinally
2411: if (n.implements TryCatchFinally()) {
2412: out.popIndent(); // try
2413: out.printil("} catch (Throwable _jspx_exception) {");
2414: out.pushIndent();
2415:
2416: out.printin("while (");
2417: out.print(tagPushBodyCountVar);
2418: out.println("[0]-- > 0)");
2419: out.pushIndent();
2420: out.printil("out = _jspx_page_context.popBody();");
2421: out.popIndent();
2422:
2423: out.printin(tagHandlerVar);
2424: out.println(".doCatch(_jspx_exception);");
2425: out.popIndent();
2426: out.printil("} finally {");
2427: out.pushIndent();
2428: out.printin(tagHandlerVar);
2429: out.println(".doFinally();");
2430: }
2431:
2432: if (isPoolingEnabled) {
2433: out.printin(n.getTagHandlerPoolName());
2434: out.print(".reuse(");
2435: out.print(tagHandlerVar);
2436: out.println(");");
2437: } else {
2438: out.printin(tagHandlerVar);
2439: out.println(".release();");
2440: out
2441: .printin("org.apache.jasper.runtime.AnnotationHelper.preDestroy(");
2442: out.print(VAR_ANNOTATIONPROCESSOR);
2443: out.print(", ");
2444: out.print(tagHandlerVar);
2445: out.println(");");
2446: }
2447:
2448: if (n.implements TryCatchFinally()) {
2449: out.popIndent();
2450: out.printil("}");
2451: }
2452:
2453: // Declare and synchronize AT_END scripting variables (must do this
2454: // outside the try/catch/finally block)
2455: declareScriptingVars(n, VariableInfo.AT_END);
2456: syncScriptingVars(n, VariableInfo.AT_END);
2457:
2458: restoreScriptingVars(n, VariableInfo.AT_BEGIN);
2459: }
2460:
2461: private void generateCustomDoTag(Node.CustomTag n,
2462: TagHandlerInfo handlerInfo, String tagHandlerVar)
2463: throws JasperException {
2464:
2465: Class tagHandlerClass = handlerInfo.getTagHandlerClass();
2466:
2467: n.setBeginJavaLine(out.getJavaLine());
2468: out.printin("// ");
2469: out.println(n.getQName());
2470:
2471: // Declare AT_BEGIN scripting variables
2472: declareScriptingVars(n, VariableInfo.AT_BEGIN);
2473: saveScriptingVars(n, VariableInfo.AT_BEGIN);
2474:
2475: String tagHandlerClassName = JspUtil
2476: .getCanonicalName(tagHandlerClass);
2477: out.printin(tagHandlerClassName);
2478: out.print(" ");
2479: out.print(tagHandlerVar);
2480: out.print(" = ");
2481: out.print("new ");
2482: out.print(tagHandlerClassName);
2483: out.println("();");
2484:
2485: // Resource injection
2486: out
2487: .printin("org.apache.jasper.runtime.AnnotationHelper.postConstruct(");
2488: out.print(VAR_ANNOTATIONPROCESSOR);
2489: out.print(", ");
2490: out.print(tagHandlerVar);
2491: out.println(");");
2492:
2493: generateSetters(n, tagHandlerVar, handlerInfo, true);
2494:
2495: // JspIdConsumer (after context has been set)
2496: if (n.implements JspIdConsumer()) {
2497: out.printin(tagHandlerVar);
2498: out.print(".setJspId(\"");
2499: out.print(createJspId());
2500: out.println("\");");
2501: }
2502:
2503: // Set the body
2504: if (findJspBody(n) == null) {
2505: /*
2506: * Encapsulate body of custom tag invocation in JspFragment and
2507: * pass it to tag handler's setJspBody(), unless tag body is
2508: * empty
2509: */
2510: if (!n.hasEmptyBody()) {
2511: out.printin(tagHandlerVar);
2512: out.print(".setJspBody(");
2513: generateJspFragment(n, tagHandlerVar);
2514: out.println(");");
2515: }
2516: } else {
2517: /*
2518: * Body of tag is the body of the <jsp:body> element. The visit
2519: * method for that element is going to encapsulate that
2520: * element's body in a JspFragment and pass it to the tag
2521: * handler's setJspBody()
2522: */
2523: String tmpTagHandlerVar = simpleTagHandlerVar;
2524: simpleTagHandlerVar = tagHandlerVar;
2525: boolean tmpIsSimpleTagHandler = isSimpleTagHandler;
2526: isSimpleTagHandler = true;
2527: visitBody(n);
2528: simpleTagHandlerVar = tmpTagHandlerVar;
2529: isSimpleTagHandler = tmpIsSimpleTagHandler;
2530: }
2531:
2532: out.printin(tagHandlerVar);
2533: out.println(".doTag();");
2534:
2535: restoreScriptingVars(n, VariableInfo.AT_BEGIN);
2536:
2537: // Synchronize AT_BEGIN scripting variables
2538: syncScriptingVars(n, VariableInfo.AT_BEGIN);
2539:
2540: // Declare and synchronize AT_END scripting variables
2541: declareScriptingVars(n, VariableInfo.AT_END);
2542: syncScriptingVars(n, VariableInfo.AT_END);
2543:
2544: // Resource injection
2545: out
2546: .printin("org.apache.jasper.runtime.AnnotationHelper.preDestroy(");
2547: out.print(VAR_ANNOTATIONPROCESSOR);
2548: out.print(", ");
2549: out.print(tagHandlerVar);
2550: out.println(");");
2551:
2552: n.setEndJavaLine(out.getJavaLine());
2553: }
2554:
2555: private void declareScriptingVars(Node.CustomTag n, int scope) {
2556:
2557: Vector vec = n.getScriptingVars(scope);
2558: if (vec != null) {
2559: for (int i = 0; i < vec.size(); i++) {
2560: Object elem = vec.elementAt(i);
2561: if (elem instanceof VariableInfo) {
2562: VariableInfo varInfo = (VariableInfo) elem;
2563: if (varInfo.getDeclare()) {
2564: out.printin(varInfo.getClassName());
2565: out.print(" ");
2566: out.print(varInfo.getVarName());
2567: out.println(" = null;");
2568: }
2569: } else {
2570: TagVariableInfo tagVarInfo = (TagVariableInfo) elem;
2571: if (tagVarInfo.getDeclare()) {
2572: String varName = tagVarInfo.getNameGiven();
2573: if (varName == null) {
2574: varName = n
2575: .getTagData()
2576: .getAttributeString(
2577: tagVarInfo
2578: .getNameFromAttribute());
2579: } else if (tagVarInfo
2580: .getNameFromAttribute() != null) {
2581: // alias
2582: continue;
2583: }
2584: out.printin(tagVarInfo.getClassName());
2585: out.print(" ");
2586: out.print(varName);
2587: out.println(" = null;");
2588: }
2589: }
2590: }
2591: }
2592: }
2593:
2594: /*
2595: * This method is called as part of the custom tag's start element.
2596: *
2597: * If the given custom tag has a custom nesting level greater than 0,
2598: * save the current values of its scripting variables to temporary
2599: * variables, so those values may be restored in the tag's end element.
2600: * This way, the scripting variables may be synchronized by the given
2601: * tag without affecting their original values.
2602: */
2603: private void saveScriptingVars(Node.CustomTag n, int scope) {
2604: if (n.getCustomNestingLevel() == 0) {
2605: return;
2606: }
2607:
2608: TagVariableInfo[] tagVarInfos = n.getTagVariableInfos();
2609: VariableInfo[] varInfos = n.getVariableInfos();
2610: if ((varInfos.length == 0) && (tagVarInfos.length == 0)) {
2611: return;
2612: }
2613:
2614: if (varInfos.length > 0) {
2615: for (int i = 0; i < varInfos.length; i++) {
2616: if (varInfos[i].getScope() != scope)
2617: continue;
2618: // If the scripting variable has been declared, skip codes
2619: // for saving and restoring it.
2620: if (n.getScriptingVars(scope).contains(varInfos[i]))
2621: continue;
2622: String varName = varInfos[i].getVarName();
2623: String tmpVarName = "_jspx_" + varName + "_"
2624: + n.getCustomNestingLevel();
2625: out.printin(tmpVarName);
2626: out.print(" = ");
2627: out.print(varName);
2628: out.println(";");
2629: }
2630: } else {
2631: for (int i = 0; i < tagVarInfos.length; i++) {
2632: if (tagVarInfos[i].getScope() != scope)
2633: continue;
2634: // If the scripting variable has been declared, skip codes
2635: // for saving and restoring it.
2636: if (n.getScriptingVars(scope).contains(
2637: tagVarInfos[i]))
2638: continue;
2639: String varName = tagVarInfos[i].getNameGiven();
2640: if (varName == null) {
2641: varName = n.getTagData().getAttributeString(
2642: tagVarInfos[i].getNameFromAttribute());
2643: } else if (tagVarInfos[i].getNameFromAttribute() != null) {
2644: // alias
2645: continue;
2646: }
2647: String tmpVarName = "_jspx_" + varName + "_"
2648: + n.getCustomNestingLevel();
2649: out.printin(tmpVarName);
2650: out.print(" = ");
2651: out.print(varName);
2652: out.println(";");
2653: }
2654: }
2655: }
2656:
2657: /*
2658: * This method is called as part of the custom tag's end element.
2659: *
2660: * If the given custom tag has a custom nesting level greater than 0,
2661: * restore its scripting variables to their original values that were
2662: * saved in the tag's start element.
2663: */
2664: private void restoreScriptingVars(Node.CustomTag n, int scope) {
2665: if (n.getCustomNestingLevel() == 0) {
2666: return;
2667: }
2668:
2669: TagVariableInfo[] tagVarInfos = n.getTagVariableInfos();
2670: VariableInfo[] varInfos = n.getVariableInfos();
2671: if ((varInfos.length == 0) && (tagVarInfos.length == 0)) {
2672: return;
2673: }
2674:
2675: if (varInfos.length > 0) {
2676: for (int i = 0; i < varInfos.length; i++) {
2677: if (varInfos[i].getScope() != scope)
2678: continue;
2679: // If the scripting variable has been declared, skip codes
2680: // for saving and restoring it.
2681: if (n.getScriptingVars(scope).contains(varInfos[i]))
2682: continue;
2683: String varName = varInfos[i].getVarName();
2684: String tmpVarName = "_jspx_" + varName + "_"
2685: + n.getCustomNestingLevel();
2686: out.printin(varName);
2687: out.print(" = ");
2688: out.print(tmpVarName);
2689: out.println(";");
2690: }
2691: } else {
2692: for (int i = 0; i < tagVarInfos.length; i++) {
2693: if (tagVarInfos[i].getScope() != scope)
2694: continue;
2695: // If the scripting variable has been declared, skip codes
2696: // for saving and restoring it.
2697: if (n.getScriptingVars(scope).contains(
2698: tagVarInfos[i]))
2699: continue;
2700: String varName = tagVarInfos[i].getNameGiven();
2701: if (varName == null) {
2702: varName = n.getTagData().getAttributeString(
2703: tagVarInfos[i].getNameFromAttribute());
2704: } else if (tagVarInfos[i].getNameFromAttribute() != null) {
2705: // alias
2706: continue;
2707: }
2708: String tmpVarName = "_jspx_" + varName + "_"
2709: + n.getCustomNestingLevel();
2710: out.printin(varName);
2711: out.print(" = ");
2712: out.print(tmpVarName);
2713: out.println(";");
2714: }
2715: }
2716: }
2717:
2718: /*
2719: * Synchronizes the scripting variables of the given custom tag for the
2720: * given scope.
2721: */
2722: private void syncScriptingVars(Node.CustomTag n, int scope) {
2723: TagVariableInfo[] tagVarInfos = n.getTagVariableInfos();
2724: VariableInfo[] varInfos = n.getVariableInfos();
2725:
2726: if ((varInfos.length == 0) && (tagVarInfos.length == 0)) {
2727: return;
2728: }
2729:
2730: if (varInfos.length > 0) {
2731: for (int i = 0; i < varInfos.length; i++) {
2732: if (varInfos[i].getScope() == scope) {
2733: out.printin(varInfos[i].getVarName());
2734: out.print(" = (");
2735: out.print(varInfos[i].getClassName());
2736: out
2737: .print(") _jspx_page_context.findAttribute(");
2738: out.print(quote(varInfos[i].getVarName()));
2739: out.println(");");
2740: }
2741: }
2742: } else {
2743: for (int i = 0; i < tagVarInfos.length; i++) {
2744: if (tagVarInfos[i].getScope() == scope) {
2745: String name = tagVarInfos[i].getNameGiven();
2746: if (name == null) {
2747: name = n.getTagData().getAttributeString(
2748: tagVarInfos[i]
2749: .getNameFromAttribute());
2750: } else if (tagVarInfos[i]
2751: .getNameFromAttribute() != null) {
2752: // alias
2753: continue;
2754: }
2755: out.printin(name);
2756: out.print(" = (");
2757: out.print(tagVarInfos[i].getClassName());
2758: out
2759: .print(") _jspx_page_context.findAttribute(");
2760: out.print(quote(name));
2761: out.println(");");
2762: }
2763: }
2764: }
2765: }
2766:
2767: private String getJspContextVar() {
2768: if (this .isTagFile) {
2769: return "this.getJspContext()";
2770: } else {
2771: return "_jspx_page_context";
2772: }
2773: }
2774:
2775: private String getExpressionFactoryVar() {
2776: return VAR_EXPRESSIONFACTORY;
2777: }
2778:
2779: /*
2780: * Creates a tag variable name by concatenating the given prefix and
2781: * shortName and endcoded to make the resultant string a valid Java
2782: * Identifier.
2783: */
2784: private String createTagVarName(String fullName, String prefix,
2785: String shortName) {
2786:
2787: String varName;
2788: synchronized (tagVarNumbers) {
2789: varName = prefix + "_" + shortName + "_";
2790: if (tagVarNumbers.get(fullName) != null) {
2791: Integer i = (Integer) tagVarNumbers.get(fullName);
2792: varName = varName + i.intValue();
2793: tagVarNumbers.put(fullName, new Integer(i
2794: .intValue() + 1));
2795: } else {
2796: tagVarNumbers.put(fullName, new Integer(1));
2797: varName = varName + "0";
2798: }
2799: }
2800: return JspUtil.makeJavaIdentifier(varName);
2801: }
2802:
2803: private String evaluateAttribute(TagHandlerInfo handlerInfo,
2804: Node.JspAttribute attr, Node.CustomTag n,
2805: String tagHandlerVar) throws JasperException {
2806:
2807: String attrValue = attr.getValue();
2808: if (attrValue == null) {
2809: if (attr.isNamedAttribute()) {
2810: if (n.checkIfAttributeIsJspFragment(attr.getName())) {
2811: // XXX - no need to generate temporary variable here
2812: attrValue = generateNamedAttributeJspFragment(
2813: attr.getNamedAttributeNode(),
2814: tagHandlerVar);
2815: } else {
2816: attrValue = generateNamedAttributeValue(attr
2817: .getNamedAttributeNode());
2818: }
2819: } else {
2820: return null;
2821: }
2822: }
2823:
2824: String localName = attr.getLocalName();
2825:
2826: Method m = null;
2827: Class[] c = null;
2828: if (attr.isDynamic()) {
2829: c = OBJECT_CLASS;
2830: } else {
2831: m = handlerInfo.getSetterMethod(localName);
2832: if (m == null) {
2833: err.jspError(n, "jsp.error.unable.to_find_method",
2834: attr.getName());
2835: }
2836: c = m.getParameterTypes();
2837: // XXX assert(c.length > 0)
2838: }
2839:
2840: if (attr.isExpression()) {
2841: // Do nothing
2842: } else if (attr.isNamedAttribute()) {
2843: if (!n.checkIfAttributeIsJspFragment(attr.getName())
2844: && !attr.isDynamic()) {
2845: attrValue = convertString(c[0], attrValue,
2846: localName, handlerInfo
2847: .getPropertyEditorClass(localName),
2848: true);
2849: }
2850: } else if (attr.isELInterpreterInput()) {
2851:
2852: // results buffer
2853: StringBuffer sb = new StringBuffer(64);
2854:
2855: TagAttributeInfo tai = attr.getTagAttributeInfo();
2856:
2857: // generate elContext reference
2858: sb.append(getJspContextVar());
2859: sb.append(".getELContext()");
2860: String elContext = sb.toString();
2861: if (attr.getEL() != null
2862: && attr.getEL().getMapName() != null) {
2863: sb.setLength(0);
2864: sb
2865: .append("new org.apache.jasper.el.ELContextWrapper(");
2866: sb.append(elContext);
2867: sb.append(',');
2868: sb.append(attr.getEL().getMapName());
2869: sb.append(')');
2870: elContext = sb.toString();
2871: }
2872:
2873: // reset buffer
2874: sb.setLength(0);
2875:
2876: // create our mark
2877: sb.append(n.getStart().toString());
2878: sb.append(" '");
2879: sb.append(attrValue);
2880: sb.append('\'');
2881: String mark = sb.toString();
2882:
2883: // reset buffer
2884: sb.setLength(0);
2885:
2886: // depending on type
2887: if (attr.isDeferredInput()
2888: || ((tai != null) && ValueExpression.class
2889: .getName().equals(tai.getTypeName()))) {
2890: sb
2891: .append("new org.apache.jasper.el.JspValueExpression(");
2892: sb.append(quote(mark));
2893: sb.append(',');
2894: sb.append(getExpressionFactoryVar());
2895: sb.append(".createValueExpression(");
2896: if (attr.getEL() != null) { // optimize
2897: sb.append(elContext);
2898: sb.append(',');
2899: }
2900: sb.append(quote(attrValue));
2901: sb.append(',');
2902: sb.append(JspUtil.toJavaSourceTypeFromTld(attr
2903: .getExpectedTypeName()));
2904: sb.append("))");
2905: // should the expression be evaluated before passing to
2906: // the setter?
2907: boolean evaluate = false;
2908: if (tai.canBeRequestTime()) {
2909: evaluate = true; // JSP.2.3.2
2910: }
2911: if (attr.isDeferredInput()) {
2912: evaluate = false; // JSP.2.3.3
2913: }
2914: if (attr.isDeferredInput()
2915: && tai.canBeRequestTime()) {
2916: evaluate = !attrValue.contains("#{"); // JSP.2.3.5
2917: }
2918: if (evaluate) {
2919: sb.append(".getValue(");
2920: sb.append(getJspContextVar());
2921: sb.append(".getELContext()");
2922: sb.append(")");
2923: }
2924: attrValue = sb.toString();
2925: } else if (attr.isDeferredMethodInput()
2926: || ((tai != null) && MethodExpression.class
2927: .getName().equals(tai.getTypeName()))) {
2928: sb
2929: .append("new org.apache.jasper.el.JspMethodExpression(");
2930: sb.append(quote(mark));
2931: sb.append(',');
2932: sb.append(getExpressionFactoryVar());
2933: sb.append(".createMethodExpression(");
2934: sb.append(elContext);
2935: sb.append(',');
2936: sb.append(quote(attrValue));
2937: sb.append(',');
2938: sb.append(JspUtil.toJavaSourceTypeFromTld(attr
2939: .getExpectedTypeName()));
2940: sb.append(',');
2941: sb.append("new Class[] {");
2942:
2943: String[] p = attr.getParameterTypeNames();
2944: for (int i = 0; i < p.length; i++) {
2945: sb
2946: .append(JspUtil
2947: .toJavaSourceTypeFromTld(p[i]));
2948: sb.append(',');
2949: }
2950: if (p.length > 0) {
2951: sb.setLength(sb.length() - 1);
2952: }
2953:
2954: sb.append("}))");
2955: attrValue = sb.toString();
2956: } else {
2957: // run attrValue through the expression interpreter
2958: boolean replaceESC = attrValue
2959: .indexOf(Constants.ESC) > 0;
2960: String mapName = (attr.getEL() != null) ? attr
2961: .getEL().getMapName() : null;
2962: attrValue = JspUtil.interpreterCall(this .isTagFile,
2963: attrValue, c[0], mapName, false);
2964: // XXX hack: Replace ESC with '$'
2965: if (replaceESC) {
2966: attrValue = "(" + attrValue + ").replace("
2967: + Constants.ESCStr + ", '$')";
2968: }
2969: }
2970: } else {
2971: attrValue = convertString(c[0], attrValue, localName,
2972: handlerInfo.getPropertyEditorClass(localName),
2973: false);
2974: }
2975: return attrValue;
2976: }
2977:
2978: /**
2979: * Generate code to create a map for the alias variables
2980: *
2981: * @return the name of the map
2982: */
2983: private String generateAliasMap(Node.CustomTag n,
2984: String tagHandlerVar) throws JasperException {
2985:
2986: TagVariableInfo[] tagVars = n.getTagVariableInfos();
2987: String aliasMapVar = null;
2988:
2989: boolean aliasSeen = false;
2990: for (int i = 0; i < tagVars.length; i++) {
2991:
2992: String nameFrom = tagVars[i].getNameFromAttribute();
2993: if (nameFrom != null) {
2994: String aliasedName = n.getAttributeValue(nameFrom);
2995: if (aliasedName == null)
2996: continue;
2997:
2998: if (!aliasSeen) {
2999: out.printin("java.util.HashMap ");
3000: aliasMapVar = tagHandlerVar + "_aliasMap";
3001: out.print(aliasMapVar);
3002: out.println(" = new java.util.HashMap();");
3003: aliasSeen = true;
3004: }
3005: out.printin(aliasMapVar);
3006: out.print(".put(");
3007: out.print(quote(tagVars[i].getNameGiven()));
3008: out.print(", ");
3009: out.print(quote(aliasedName));
3010: out.println(");");
3011: }
3012: }
3013: return aliasMapVar;
3014: }
3015:
3016: private void generateSetters(Node.CustomTag n,
3017: String tagHandlerVar, TagHandlerInfo handlerInfo,
3018: boolean simpleTag) throws JasperException {
3019:
3020: // Set context
3021: if (simpleTag) {
3022: // Generate alias map
3023: String aliasMapVar = null;
3024: if (n.isTagFile()) {
3025: aliasMapVar = generateAliasMap(n, tagHandlerVar);
3026: }
3027: out.printin(tagHandlerVar);
3028: if (aliasMapVar == null) {
3029: out.println(".setJspContext(_jspx_page_context);");
3030: } else {
3031: out.print(".setJspContext(_jspx_page_context, ");
3032: out.print(aliasMapVar);
3033: out.println(");");
3034: }
3035: } else {
3036: out.printin(tagHandlerVar);
3037: out.println(".setPageContext(_jspx_page_context);");
3038: }
3039:
3040: // Set parent
3041: if (isTagFile && parent == null) {
3042: out.printin(tagHandlerVar);
3043: out.print(".setParent(");
3044: out.print("new javax.servlet.jsp.tagext.TagAdapter(");
3045: out
3046: .print("(javax.servlet.jsp.tagext.SimpleTag) this ));");
3047: } else if (!simpleTag) {
3048: out.printin(tagHandlerVar);
3049: out.print(".setParent(");
3050: if (parent != null) {
3051: if (isSimpleTagParent) {
3052: out
3053: .print("new javax.servlet.jsp.tagext.TagAdapter(");
3054: out
3055: .print("(javax.servlet.jsp.tagext.SimpleTag) ");
3056: out.print(parent);
3057: out.println("));");
3058: } else {
3059: out.print("(javax.servlet.jsp.tagext.Tag) ");
3060: out.print(parent);
3061: out.println(");");
3062: }
3063: } else {
3064: out.println("null);");
3065: }
3066: } else {
3067: // The setParent() method need not be called if the value being
3068: // passed is null, since SimpleTag instances are not reused
3069: if (parent != null) {
3070: out.printin(tagHandlerVar);
3071: out.print(".setParent(");
3072: out.print(parent);
3073: out.println(");");
3074: }
3075: }
3076:
3077: // need to handle deferred values and methods
3078: Node.JspAttribute[] attrs = n.getJspAttributes();
3079: for (int i = 0; attrs != null && i < attrs.length; i++) {
3080: String attrValue = evaluateAttribute(handlerInfo,
3081: attrs[i], n, tagHandlerVar);
3082:
3083: Mark m = n.getStart();
3084: out.printil("// " + m.getFile() + "("
3085: + m.getLineNumber() + "," + m.getColumnNumber()
3086: + ") " + attrs[i].getTagAttributeInfo());
3087: if (attrs[i].isDynamic()) {
3088: out.printin(tagHandlerVar);
3089: out.print(".");
3090: out.print("setDynamicAttribute(");
3091: String uri = attrs[i].getURI();
3092: if ("".equals(uri) || (uri == null)) {
3093: out.print("null");
3094: } else {
3095: out.print("\"" + attrs[i].getURI() + "\"");
3096: }
3097: out.print(", \"");
3098: out.print(attrs[i].getLocalName());
3099: out.print("\", ");
3100: out.print(attrValue);
3101: out.println(");");
3102: } else {
3103: out.printin(tagHandlerVar);
3104: out.print(".");
3105: out.print(handlerInfo.getSetterMethod(
3106: attrs[i].getLocalName()).getName());
3107: out.print("(");
3108: out.print(attrValue);
3109: out.println(");");
3110: }
3111: }
3112: }
3113:
3114: /*
3115: * @param c The target class to which to coerce the given string @param
3116: * s The string value @param attrName The name of the attribute whose
3117: * value is being supplied @param propEditorClass The property editor
3118: * for the given attribute @param isNamedAttribute true if the given
3119: * attribute is a named attribute (that is, specified using the
3120: * jsp:attribute standard action), and false otherwise
3121: */
3122: private String convertString(Class c, String s,
3123: String attrName, Class propEditorClass,
3124: boolean isNamedAttribute) throws JasperException {
3125:
3126: String quoted = s;
3127: if (!isNamedAttribute) {
3128: quoted = quote(s);
3129: }
3130:
3131: if (propEditorClass != null) {
3132: String className = JspUtil.getCanonicalName(c);
3133: return "("
3134: + className
3135: + ")org.apache.jasper.runtime.JspRuntimeLibrary.getValueFromBeanInfoPropertyEditor("
3136: + className + ".class, \"" + attrName + "\", "
3137: + quoted + ", "
3138: + JspUtil.getCanonicalName(propEditorClass)
3139: + ".class)";
3140: } else if (c == String.class) {
3141: return quoted;
3142: } else if (c == boolean.class) {
3143: return JspUtil.coerceToPrimitiveBoolean(s,
3144: isNamedAttribute);
3145: } else if (c == Boolean.class) {
3146: return JspUtil.coerceToBoolean(s, isNamedAttribute);
3147: } else if (c == byte.class) {
3148: return JspUtil.coerceToPrimitiveByte(s,
3149: isNamedAttribute);
3150: } else if (c == Byte.class) {
3151: return JspUtil.coerceToByte(s, isNamedAttribute);
3152: } else if (c == char.class) {
3153: return JspUtil.coerceToChar(s, isNamedAttribute);
3154: } else if (c == Character.class) {
3155: return JspUtil.coerceToCharacter(s, isNamedAttribute);
3156: } else if (c == double.class) {
3157: return JspUtil.coerceToPrimitiveDouble(s,
3158: isNamedAttribute);
3159: } else if (c == Double.class) {
3160: return JspUtil.coerceToDouble(s, isNamedAttribute);
3161: } else if (c == float.class) {
3162: return JspUtil.coerceToPrimitiveFloat(s,
3163: isNamedAttribute);
3164: } else if (c == Float.class) {
3165: return JspUtil.coerceToFloat(s, isNamedAttribute);
3166: } else if (c == int.class) {
3167: return JspUtil.coerceToInt(s, isNamedAttribute);
3168: } else if (c == Integer.class) {
3169: return JspUtil.coerceToInteger(s, isNamedAttribute);
3170: } else if (c == short.class) {
3171: return JspUtil.coerceToPrimitiveShort(s,
3172: isNamedAttribute);
3173: } else if (c == Short.class) {
3174: return JspUtil.coerceToShort(s, isNamedAttribute);
3175: } else if (c == long.class) {
3176: return JspUtil.coerceToPrimitiveLong(s,
3177: isNamedAttribute);
3178: } else if (c == Long.class) {
3179: return JspUtil.coerceToLong(s, isNamedAttribute);
3180: } else if (c == Object.class) {
3181: return "new String(" + quoted + ")";
3182: } else {
3183: String className = JspUtil.getCanonicalName(c);
3184: return "("
3185: + className
3186: + ")org.apache.jasper.runtime.JspRuntimeLibrary.getValueFromPropertyEditorManager("
3187: + className + ".class, \"" + attrName + "\", "
3188: + quoted + ")";
3189: }
3190: }
3191:
3192: /*
3193: * Converts the scope string representation, whose possible values are
3194: * "page", "request", "session", and "application", to the corresponding
3195: * scope constant.
3196: */
3197: private String getScopeConstant(String scope) {
3198: String scopeName = "PageContext.PAGE_SCOPE"; // Default to page
3199:
3200: if ("request".equals(scope)) {
3201: scopeName = "PageContext.REQUEST_SCOPE";
3202: } else if ("session".equals(scope)) {
3203: scopeName = "PageContext.SESSION_SCOPE";
3204: } else if ("application".equals(scope)) {
3205: scopeName = "PageContext.APPLICATION_SCOPE";
3206: }
3207:
3208: return scopeName;
3209: }
3210:
3211: /**
3212: * Generates anonymous JspFragment inner class which is passed as an
3213: * argument to SimpleTag.setJspBody().
3214: */
3215: private void generateJspFragment(Node n, String tagHandlerVar)
3216: throws JasperException {
3217: // XXX - A possible optimization here would be to check to see
3218: // if the only child of the parent node is TemplateText. If so,
3219: // we know there won't be any parameters, etc, so we can
3220: // generate a low-overhead JspFragment that just echoes its
3221: // body. The implementation of this fragment can come from
3222: // the org.apache.jasper.runtime package as a support class.
3223: FragmentHelperClass.Fragment fragment = fragmentHelperClass
3224: .openFragment(n, tagHandlerVar, methodNesting);
3225: ServletWriter outSave = out;
3226: out = fragment.getGenBuffer().getOut();
3227: String tmpParent = parent;
3228: parent = "_jspx_parent";
3229: boolean isSimpleTagParentSave = isSimpleTagParent;
3230: isSimpleTagParent = true;
3231: boolean tmpIsFragment = isFragment;
3232: isFragment = true;
3233: String pushBodyCountVarSave = pushBodyCountVar;
3234: if (pushBodyCountVar != null) {
3235: // Use a fixed name for push body count, to simplify code gen
3236: pushBodyCountVar = "_jspx_push_body_count";
3237: }
3238: visitBody(n);
3239: out = outSave;
3240: parent = tmpParent;
3241: isSimpleTagParent = isSimpleTagParentSave;
3242: isFragment = tmpIsFragment;
3243: pushBodyCountVar = pushBodyCountVarSave;
3244: fragmentHelperClass.closeFragment(fragment, methodNesting);
3245: // XXX - Need to change pageContext to jspContext if
3246: // we're not in a place where pageContext is defined (e.g.
3247: // in a fragment or in a tag file.
3248: out.print("new " + fragmentHelperClass.getClassName()
3249: + "( " + fragment.getId()
3250: + ", _jspx_page_context, " + tagHandlerVar + ", "
3251: + pushBodyCountVar + ")");
3252: }
3253:
3254: /**
3255: * Generate the code required to obtain the runtime value of the given
3256: * named attribute.
3257: *
3258: * @return The name of the temporary variable the result is stored in.
3259: */
3260: public String generateNamedAttributeValue(Node.NamedAttribute n)
3261: throws JasperException {
3262:
3263: String varName = n.getTemporaryVariableName();
3264:
3265: // If the only body element for this named attribute node is
3266: // template text, we need not generate an extra call to
3267: // pushBody and popBody. Maybe we can further optimize
3268: // here by getting rid of the temporary variable, but in
3269: // reality it looks like javac does this for us.
3270: Node.Nodes body = n.getBody();
3271: if (body != null) {
3272: boolean templateTextOptimization = false;
3273: if (body.size() == 1) {
3274: Node bodyElement = body.getNode(0);
3275: if (bodyElement instanceof Node.TemplateText) {
3276: templateTextOptimization = true;
3277: out
3278: .printil("String "
3279: + varName
3280: + " = "
3281: + quote(new String(
3282: ((Node.TemplateText) bodyElement)
3283: .getText()))
3284: + ";");
3285: }
3286: }
3287:
3288: // XXX - Another possible optimization would be for
3289: // lone EL expressions (no need to pushBody here either).
3290:
3291: if (!templateTextOptimization) {
3292: out.printil("out = _jspx_page_context.pushBody();");
3293: visitBody(n);
3294: out.printil("String " + varName + " = "
3295: + "((javax.servlet.jsp.tagext.BodyContent)"
3296: + "out).getString();");
3297: out.printil("out = _jspx_page_context.popBody();");
3298: }
3299: } else {
3300: // Empty body must be treated as ""
3301: out.printil("String " + varName + " = \"\";");
3302: }
3303:
3304: return varName;
3305: }
3306:
3307: /**
3308: * Similar to generateNamedAttributeValue, but create a JspFragment
3309: * instead.
3310: *
3311: * @param n
3312: * The parent node of the named attribute
3313: * @param tagHandlerVar
3314: * The variable the tag handler is stored in, so the fragment
3315: * knows its parent tag.
3316: * @return The name of the temporary variable the fragment is stored in.
3317: */
3318: public String generateNamedAttributeJspFragment(
3319: Node.NamedAttribute n, String tagHandlerVar)
3320: throws JasperException {
3321: String varName = n.getTemporaryVariableName();
3322:
3323: out.printin("javax.servlet.jsp.tagext.JspFragment "
3324: + varName + " = ");
3325: generateJspFragment(n, tagHandlerVar);
3326: out.println(";");
3327:
3328: return varName;
3329: }
3330: }
3331:
3332: private static void generateLocalVariables(ServletWriter out, Node n)
3333: throws JasperException {
3334: Node.ChildInfo ci;
3335: if (n instanceof Node.CustomTag) {
3336: ci = ((Node.CustomTag) n).getChildInfo();
3337: } else if (n instanceof Node.JspBody) {
3338: ci = ((Node.JspBody) n).getChildInfo();
3339: } else if (n instanceof Node.NamedAttribute) {
3340: ci = ((Node.NamedAttribute) n).getChildInfo();
3341: } else {
3342: // Cannot access err since this method is static, but at
3343: // least flag an error.
3344: throw new JasperException("Unexpected Node Type");
3345: // err.getString(
3346: // "jsp.error.internal.unexpected_node_type" ) );
3347: }
3348:
3349: if (ci.hasUseBean()) {
3350: out
3351: .printil("HttpSession session = _jspx_page_context.getSession();");
3352: out
3353: .printil("ServletContext application = _jspx_page_context.getServletContext();");
3354: }
3355: if (ci.hasUseBean() || ci.hasIncludeAction()
3356: || ci.hasSetProperty() || ci.hasParamAction()) {
3357: out
3358: .printil("HttpServletRequest request = (HttpServletRequest)_jspx_page_context.getRequest();");
3359: }
3360: if (ci.hasIncludeAction()) {
3361: out
3362: .printil("HttpServletResponse response = (HttpServletResponse)_jspx_page_context.getResponse();");
3363: }
3364: }
3365:
3366: /**
3367: * Common part of postamble, shared by both servlets and tag files.
3368: */
3369: private void genCommonPostamble() {
3370: // Append any methods that were generated in the buffer.
3371: for (int i = 0; i < methodsBuffered.size(); i++) {
3372: GenBuffer methodBuffer = (GenBuffer) methodsBuffered.get(i);
3373: methodBuffer.adjustJavaLines(out.getJavaLine() - 1);
3374: out.printMultiLn(methodBuffer.toString());
3375: }
3376:
3377: // Append the helper class
3378: if (fragmentHelperClass.isUsed()) {
3379: fragmentHelperClass.generatePostamble();
3380: fragmentHelperClass.adjustJavaLines(out.getJavaLine() - 1);
3381: out.printMultiLn(fragmentHelperClass.toString());
3382: }
3383:
3384: // Append char array declarations
3385: if (charArrayBuffer != null) {
3386: out.printMultiLn(charArrayBuffer.toString());
3387: }
3388:
3389: // Close the class definition
3390: out.popIndent();
3391: out.printil("}");
3392: }
3393:
3394: /**
3395: * Generates the ending part of the static portion of the servlet.
3396: */
3397: private void generatePostamble(Node.Nodes page) {
3398: out.popIndent();
3399: out.printil("} catch (Throwable t) {");
3400: out.pushIndent();
3401: out.printil("if (!(t instanceof SkipPageException)){");
3402: out.pushIndent();
3403: out.printil("out = _jspx_out;");
3404: out.printil("if (out != null && out.getBufferSize() != 0)");
3405: out.pushIndent();
3406: out
3407: .printil("try { out.clearBuffer(); } catch (java.io.IOException e) {}");
3408: out.popIndent();
3409:
3410: out
3411: .printil("if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);");
3412: out.popIndent();
3413: out.printil("}");
3414: out.popIndent();
3415: out.printil("} finally {");
3416: out.pushIndent();
3417:
3418: out
3419: .printil("_jspxFactory.releasePageContext(_jspx_page_context);");
3420:
3421: out.popIndent();
3422: out.printil("}");
3423:
3424: // Close the service method
3425: out.popIndent();
3426: out.printil("}");
3427:
3428: // Generated methods, helper classes, etc.
3429: genCommonPostamble();
3430: }
3431:
3432: /**
3433: * Constructor.
3434: */
3435: Generator(ServletWriter out, Compiler compiler) {
3436: this .out = out;
3437: methodsBuffered = new ArrayList();
3438: charArrayBuffer = null;
3439: err = compiler.getErrorDispatcher();
3440: ctxt = compiler.getCompilationContext();
3441: fragmentHelperClass = new FragmentHelperClass(ctxt
3442: .getServletClassName()
3443: + "Helper");
3444: pageInfo = compiler.getPageInfo();
3445:
3446: /*
3447: * Temporary hack. If a JSP page uses the "extends" attribute of the
3448: * page directive, the _jspInit() method of the generated servlet class
3449: * will not be called (it is only called for those generated servlets
3450: * that extend HttpJspBase, the default), causing the tag handler pools
3451: * not to be initialized and resulting in a NPE. The JSP spec needs to
3452: * clarify whether containers can override init() and destroy(). For
3453: * now, we just disable tag pooling for pages that use "extends".
3454: */
3455: if (pageInfo.getExtends(false) == null) {
3456: isPoolingEnabled = ctxt.getOptions().isPoolingEnabled();
3457: } else {
3458: isPoolingEnabled = false;
3459: }
3460: beanInfo = pageInfo.getBeanRepository();
3461: breakAtLF = ctxt.getOptions().getMappedFile();
3462: if (isPoolingEnabled) {
3463: tagHandlerPoolNames = new Vector();
3464: }
3465: }
3466:
3467: /**
3468: * The main entry for Generator.
3469: *
3470: * @param out
3471: * The servlet output writer
3472: * @param compiler
3473: * The compiler
3474: * @param page
3475: * The input page
3476: */
3477: public static void generate(ServletWriter out, Compiler compiler,
3478: Node.Nodes page) throws JasperException {
3479:
3480: Generator gen = new Generator(out, compiler);
3481:
3482: if (gen.isPoolingEnabled) {
3483: gen.compileTagHandlerPoolList(page);
3484: }
3485: if (gen.ctxt.isTagFile()) {
3486: JasperTagInfo tagInfo = (JasperTagInfo) gen.ctxt
3487: .getTagInfo();
3488: gen.generateTagHandlerPreamble(tagInfo, page);
3489:
3490: if (gen.ctxt.isPrototypeMode()) {
3491: return;
3492: }
3493:
3494: gen.generateXmlProlog(page);
3495: gen.fragmentHelperClass.generatePreamble();
3496: page.visit(gen.new GenerateVisitor(gen.ctxt.isTagFile(),
3497: out, gen.methodsBuffered, gen.fragmentHelperClass,
3498: gen.ctxt.getClassLoader(), tagInfo));
3499: gen.generateTagHandlerPostamble(tagInfo);
3500: } else {
3501: gen.generatePreamble(page);
3502: gen.generateXmlProlog(page);
3503: gen.fragmentHelperClass.generatePreamble();
3504: page.visit(gen.new GenerateVisitor(gen.ctxt.isTagFile(),
3505: out, gen.methodsBuffered, gen.fragmentHelperClass,
3506: gen.ctxt.getClassLoader(), null));
3507: gen.generatePostamble(page);
3508: }
3509: }
3510:
3511: /*
3512: * Generates tag handler preamble.
3513: */
3514: private void generateTagHandlerPreamble(JasperTagInfo tagInfo,
3515: Node.Nodes tag) throws JasperException {
3516:
3517: // Generate package declaration
3518: String className = tagInfo.getTagClassName();
3519: int lastIndex = className.lastIndexOf('.');
3520: if (lastIndex != -1) {
3521: String pkgName = className.substring(0, lastIndex);
3522: genPreamblePackage(pkgName);
3523: className = className.substring(lastIndex + 1);
3524: }
3525:
3526: // Generate imports
3527: genPreambleImports();
3528:
3529: // Generate class declaration
3530: out.printin("public final class ");
3531: out.println(className);
3532: out
3533: .printil(" extends javax.servlet.jsp.tagext.SimpleTagSupport");
3534: out
3535: .printin(" implements org.apache.jasper.runtime.JspSourceDependent");
3536: if (tagInfo.hasDynamicAttributes()) {
3537: out.println(",");
3538: out
3539: .printin(" javax.servlet.jsp.tagext.DynamicAttributes");
3540: }
3541: out.println(" {");
3542: out.println();
3543: out.pushIndent();
3544:
3545: /*
3546: * Class body begins here
3547: */
3548: generateDeclarations(tag);
3549:
3550: // Static initializations here
3551: genPreambleStaticInitializers();
3552:
3553: out.printil("private JspContext jspContext;");
3554:
3555: // Declare writer used for storing result of fragment/body invocation
3556: // if 'varReader' or 'var' attribute is specified
3557: out.printil("private java.io.Writer _jspx_sout;");
3558:
3559: // Class variable declarations
3560: genPreambleClassVariableDeclarations(tagInfo.getTagName());
3561:
3562: generateSetJspContext(tagInfo);
3563:
3564: // Tag-handler specific declarations
3565: generateTagHandlerAttributes(tagInfo);
3566: if (tagInfo.hasDynamicAttributes())
3567: generateSetDynamicAttribute();
3568:
3569: // Methods here
3570: genPreambleMethods();
3571:
3572: // Now the doTag() method
3573: out
3574: .printil("public void doTag() throws JspException, java.io.IOException {");
3575:
3576: if (ctxt.isPrototypeMode()) {
3577: out.printil("}");
3578: out.popIndent();
3579: out.printil("}");
3580: return;
3581: }
3582:
3583: out.pushIndent();
3584:
3585: /*
3586: * According to the spec, 'pageContext' must not be made available as an
3587: * implicit object in tag files. Declare _jspx_page_context, so we can
3588: * share the code generator with JSPs.
3589: */
3590: out
3591: .printil("PageContext _jspx_page_context = (PageContext)jspContext;");
3592:
3593: // Declare implicit objects.
3594: out
3595: .printil("HttpServletRequest request = "
3596: + "(HttpServletRequest) _jspx_page_context.getRequest();");
3597: out
3598: .printil("HttpServletResponse response = "
3599: + "(HttpServletResponse) _jspx_page_context.getResponse();");
3600: out
3601: .printil("HttpSession session = _jspx_page_context.getSession();");
3602: out
3603: .printil("ServletContext application = _jspx_page_context.getServletContext();");
3604: out
3605: .printil("ServletConfig config = _jspx_page_context.getServletConfig();");
3606: out.printil("JspWriter out = jspContext.getOut();");
3607: out.printil("_jspInit(config);");
3608:
3609: // set current JspContext on ELContext
3610: out
3611: .printil("jspContext.getELContext().putContext(JspContext.class,jspContext);");
3612:
3613: generatePageScopedVariables(tagInfo);
3614:
3615: declareTemporaryScriptingVars(tag);
3616: out.println();
3617:
3618: out.printil("try {");
3619: out.pushIndent();
3620: }
3621:
3622: private void generateTagHandlerPostamble(TagInfo tagInfo) {
3623: out.popIndent();
3624:
3625: // Have to catch Throwable because a classic tag handler
3626: // helper method is declared to throw Throwable.
3627: out.printil("} catch( Throwable t ) {");
3628: out.pushIndent();
3629: out.printil("if( t instanceof SkipPageException )");
3630: out.printil(" throw (SkipPageException) t;");
3631: out.printil("if( t instanceof java.io.IOException )");
3632: out.printil(" throw (java.io.IOException) t;");
3633: out.printil("if( t instanceof IllegalStateException )");
3634: out.printil(" throw (IllegalStateException) t;");
3635: out.printil("if( t instanceof JspException )");
3636: out.printil(" throw (JspException) t;");
3637: out.printil("throw new JspException(t);");
3638: out.popIndent();
3639: out.printil("} finally {");
3640: out.pushIndent();
3641:
3642: // handle restoring VariableMapper
3643: TagAttributeInfo[] attrInfos = tagInfo.getAttributes();
3644: for (int i = 0; i < attrInfos.length; i++) {
3645: if (attrInfos[i].isDeferredMethod()
3646: || attrInfos[i].isDeferredValue()) {
3647: out.printin("_el_variablemapper.setVariable(");
3648: out.print(quote(attrInfos[i].getName()));
3649: out.print(",_el_ve");
3650: out.print(i);
3651: out.println(");");
3652: }
3653: }
3654:
3655: // restore nested JspContext on ELContext
3656: out
3657: .printil("jspContext.getELContext().putContext(JspContext.class,super.getJspContext());");
3658:
3659: out
3660: .printil("((org.apache.jasper.runtime.JspContextWrapper) jspContext).syncEndTagFile();");
3661: if (isPoolingEnabled && !tagHandlerPoolNames.isEmpty()) {
3662: out.printil("_jspDestroy();");
3663: }
3664: out.popIndent();
3665: out.printil("}");
3666:
3667: // Close the doTag method
3668: out.popIndent();
3669: out.printil("}");
3670:
3671: // Generated methods, helper classes, etc.
3672: genCommonPostamble();
3673: }
3674:
3675: /**
3676: * Generates declarations for tag handler attributes, and defines the getter
3677: * and setter methods for each.
3678: */
3679: private void generateTagHandlerAttributes(TagInfo tagInfo)
3680: throws JasperException {
3681:
3682: if (tagInfo.hasDynamicAttributes()) {
3683: out
3684: .printil("private java.util.HashMap _jspx_dynamic_attrs = new java.util.HashMap();");
3685: }
3686:
3687: // Declare attributes
3688: TagAttributeInfo[] attrInfos = tagInfo.getAttributes();
3689: for (int i = 0; i < attrInfos.length; i++) {
3690: out.printin("private ");
3691: if (attrInfos[i].isFragment()) {
3692: out.print("javax.servlet.jsp.tagext.JspFragment ");
3693: } else {
3694: out.print(JspUtil.toJavaSourceType(attrInfos[i]
3695: .getTypeName()));
3696: out.print(" ");
3697: }
3698: out.print(attrInfos[i].getName());
3699: out.println(";");
3700: }
3701: out.println();
3702:
3703: // Define attribute getter and setter methods
3704: if (attrInfos != null) {
3705: for (int i = 0; i < attrInfos.length; i++) {
3706: // getter method
3707: out.printin("public ");
3708: if (attrInfos[i].isFragment()) {
3709: out.print("javax.servlet.jsp.tagext.JspFragment ");
3710: } else {
3711: out.print(JspUtil.toJavaSourceType(attrInfos[i]
3712: .getTypeName()));
3713: out.print(" ");
3714: }
3715: out.print(toGetterMethod(attrInfos[i].getName()));
3716: out.println(" {");
3717: out.pushIndent();
3718: out.printin("return this.");
3719: out.print(attrInfos[i].getName());
3720: out.println(";");
3721: out.popIndent();
3722: out.printil("}");
3723: out.println();
3724:
3725: // setter method
3726: out.printin("public void ");
3727: out.print(toSetterMethodName(attrInfos[i].getName()));
3728: if (attrInfos[i].isFragment()) {
3729: out.print("(javax.servlet.jsp.tagext.JspFragment ");
3730: } else {
3731: out.print("(");
3732: out.print(JspUtil.toJavaSourceType(attrInfos[i]
3733: .getTypeName()));
3734: out.print(" ");
3735: }
3736: out.print(attrInfos[i].getName());
3737: out.println(") {");
3738: out.pushIndent();
3739: out.printin("this.");
3740: out.print(attrInfos[i].getName());
3741: out.print(" = ");
3742: out.print(attrInfos[i].getName());
3743: out.println(";");
3744: if (ctxt.isTagFile()) {
3745: // Tag files should also set jspContext attributes
3746: out.printin("jspContext.setAttribute(\"");
3747: out.print(attrInfos[i].getName());
3748: out.print("\", ");
3749: out.print(attrInfos[i].getName());
3750: out.println(");");
3751: }
3752: out.popIndent();
3753: out.printil("}");
3754: out.println();
3755: }
3756: }
3757: }
3758:
3759: /*
3760: * Generate setter for JspContext so we can create a wrapper and store both
3761: * the original and the wrapper. We need the wrapper to mask the page
3762: * context from the tag file and simulate a fresh page context. We need the
3763: * original to do things like sync AT_BEGIN and AT_END scripting variables.
3764: */
3765: private void generateSetJspContext(TagInfo tagInfo) {
3766:
3767: boolean nestedSeen = false;
3768: boolean atBeginSeen = false;
3769: boolean atEndSeen = false;
3770:
3771: // Determine if there are any aliases
3772: boolean aliasSeen = false;
3773: TagVariableInfo[] tagVars = tagInfo.getTagVariableInfos();
3774: for (int i = 0; i < tagVars.length; i++) {
3775: if (tagVars[i].getNameFromAttribute() != null
3776: && tagVars[i].getNameGiven() != null) {
3777: aliasSeen = true;
3778: break;
3779: }
3780: }
3781:
3782: if (aliasSeen) {
3783: out
3784: .printil("public void setJspContext(JspContext ctx, java.util.Map aliasMap) {");
3785: } else {
3786: out.printil("public void setJspContext(JspContext ctx) {");
3787: }
3788: out.pushIndent();
3789: out.printil("super.setJspContext(ctx);");
3790: out.printil("java.util.ArrayList _jspx_nested = null;");
3791: out.printil("java.util.ArrayList _jspx_at_begin = null;");
3792: out.printil("java.util.ArrayList _jspx_at_end = null;");
3793:
3794: for (int i = 0; i < tagVars.length; i++) {
3795:
3796: switch (tagVars[i].getScope()) {
3797: case VariableInfo.NESTED:
3798: if (!nestedSeen) {
3799: out
3800: .printil("_jspx_nested = new java.util.ArrayList();");
3801: nestedSeen = true;
3802: }
3803: out.printin("_jspx_nested.add(");
3804: break;
3805:
3806: case VariableInfo.AT_BEGIN:
3807: if (!atBeginSeen) {
3808: out
3809: .printil("_jspx_at_begin = new java.util.ArrayList();");
3810: atBeginSeen = true;
3811: }
3812: out.printin("_jspx_at_begin.add(");
3813: break;
3814:
3815: case VariableInfo.AT_END:
3816: if (!atEndSeen) {
3817: out
3818: .printil("_jspx_at_end = new java.util.ArrayList();");
3819: atEndSeen = true;
3820: }
3821: out.printin("_jspx_at_end.add(");
3822: break;
3823: } // switch
3824:
3825: out.print(quote(tagVars[i].getNameGiven()));
3826: out.println(");");
3827: }
3828: if (aliasSeen) {
3829: out
3830: .printil("this.jspContext = new org.apache.jasper.runtime.JspContextWrapper(ctx, _jspx_nested, _jspx_at_begin, _jspx_at_end, aliasMap);");
3831: } else {
3832: out
3833: .printil("this.jspContext = new org.apache.jasper.runtime.JspContextWrapper(ctx, _jspx_nested, _jspx_at_begin, _jspx_at_end, null);");
3834: }
3835: out.popIndent();
3836: out.printil("}");
3837: out.println();
3838: out.printil("public JspContext getJspContext() {");
3839: out.pushIndent();
3840: out.printil("return this.jspContext;");
3841: out.popIndent();
3842: out.printil("}");
3843: }
3844:
3845: /*
3846: * Generates implementation of
3847: * javax.servlet.jsp.tagext.DynamicAttributes.setDynamicAttribute() method,
3848: * which saves each dynamic attribute that is passed in so that a scoped
3849: * variable can later be created for it.
3850: */
3851: public void generateSetDynamicAttribute() {
3852: out
3853: .printil("public void setDynamicAttribute(String uri, String localName, Object value) throws JspException {");
3854: out.pushIndent();
3855: /*
3856: * According to the spec, only dynamic attributes with no uri are to be
3857: * present in the Map; all other dynamic attributes are ignored.
3858: */
3859: out.printil("if (uri == null)");
3860: out.pushIndent();
3861: out.printil("_jspx_dynamic_attrs.put(localName, value);");
3862: out.popIndent();
3863: out.popIndent();
3864: out.printil("}");
3865: }
3866:
3867: /*
3868: * Creates a page-scoped variable for each declared tag attribute. Also, if
3869: * the tag accepts dynamic attributes, a page-scoped variable is made
3870: * available for each dynamic attribute that was passed in.
3871: */
3872: private void generatePageScopedVariables(JasperTagInfo tagInfo) {
3873:
3874: // "normal" attributes
3875: TagAttributeInfo[] attrInfos = tagInfo.getAttributes();
3876: boolean variableMapperVar = false;
3877: for (int i = 0; i < attrInfos.length; i++) {
3878: String attrName = attrInfos[i].getName();
3879:
3880: // handle assigning deferred vars to VariableMapper, storing
3881: // previous values under '_el_ve[i]' for later re-assignment
3882: if (attrInfos[i].isDeferredValue()
3883: || attrInfos[i].isDeferredMethod()) {
3884:
3885: // we need to scope the modified VariableMapper for consistency and performance
3886: if (!variableMapperVar) {
3887: out
3888: .printil("javax.el.VariableMapper _el_variablemapper = jspContext.getELContext().getVariableMapper();");
3889: variableMapperVar = true;
3890: }
3891:
3892: out.printin("javax.el.ValueExpression _el_ve");
3893: out.print(i);
3894: out.print(" = _el_variablemapper.setVariable(");
3895: out.print(quote(attrName));
3896: out.print(',');
3897: if (attrInfos[i].isDeferredMethod()) {
3898: out.print(VAR_EXPRESSIONFACTORY);
3899: out.print(".createValueExpression(");
3900: out.print(toGetterMethod(attrName));
3901: out.print(",javax.el.MethodExpression.class)");
3902: } else {
3903: out.print(toGetterMethod(attrName));
3904: }
3905: out.println(");");
3906: } else {
3907: out.printil("if( " + toGetterMethod(attrName)
3908: + " != null ) ");
3909: out.pushIndent();
3910: out.printin("_jspx_page_context.setAttribute(");
3911: out.print(quote(attrName));
3912: out.print(", ");
3913: out.print(toGetterMethod(attrName));
3914: out.println(");");
3915: out.popIndent();
3916: }
3917: }
3918:
3919: // Expose the Map containing dynamic attributes as a page-scoped var
3920: if (tagInfo.hasDynamicAttributes()) {
3921: out.printin("_jspx_page_context.setAttribute(\"");
3922: out.print(tagInfo.getDynamicAttributesMapName());
3923: out.print("\", _jspx_dynamic_attrs);");
3924: }
3925: }
3926:
3927: /*
3928: * Generates the getter method for the given attribute name.
3929: */
3930: private String toGetterMethod(String attrName) {
3931: char[] attrChars = attrName.toCharArray();
3932: attrChars[0] = Character.toUpperCase(attrChars[0]);
3933: return "get" + new String(attrChars) + "()";
3934: }
3935:
3936: /*
3937: * Generates the setter method name for the given attribute name.
3938: */
3939: private String toSetterMethodName(String attrName) {
3940: char[] attrChars = attrName.toCharArray();
3941: attrChars[0] = Character.toUpperCase(attrChars[0]);
3942: return "set" + new String(attrChars);
3943: }
3944:
3945: /**
3946: * Class storing the result of introspecting a custom tag handler.
3947: */
3948: private static class TagHandlerInfo {
3949:
3950: private Hashtable methodMaps;
3951:
3952: private Hashtable propertyEditorMaps;
3953:
3954: private Class tagHandlerClass;
3955:
3956: /**
3957: * Constructor.
3958: *
3959: * @param n
3960: * The custom tag whose tag handler class is to be
3961: * introspected
3962: * @param tagHandlerClass
3963: * Tag handler class
3964: * @param err
3965: * Error dispatcher
3966: */
3967: TagHandlerInfo(Node n, Class tagHandlerClass,
3968: ErrorDispatcher err) throws JasperException {
3969: this .tagHandlerClass = tagHandlerClass;
3970: this .methodMaps = new Hashtable();
3971: this .propertyEditorMaps = new Hashtable();
3972:
3973: try {
3974: BeanInfo tagClassInfo = Introspector
3975: .getBeanInfo(tagHandlerClass);
3976: PropertyDescriptor[] pd = tagClassInfo
3977: .getPropertyDescriptors();
3978: for (int i = 0; i < pd.length; i++) {
3979: /*
3980: * FIXME: should probably be checking for things like
3981: * pageContext, bodyContent, and parent here -akv
3982: */
3983: if (pd[i].getWriteMethod() != null) {
3984: methodMaps.put(pd[i].getName(), pd[i]
3985: .getWriteMethod());
3986: }
3987: if (pd[i].getPropertyEditorClass() != null)
3988: propertyEditorMaps.put(pd[i].getName(), pd[i]
3989: .getPropertyEditorClass());
3990: }
3991: } catch (IntrospectionException ie) {
3992: err.jspError(n, "jsp.error.introspect.taghandler",
3993: tagHandlerClass.getName(), ie);
3994: }
3995: }
3996:
3997: /**
3998: * XXX
3999: */
4000: public Method getSetterMethod(String attrName) {
4001: return (Method) methodMaps.get(attrName);
4002: }
4003:
4004: /**
4005: * XXX
4006: */
4007: public Class getPropertyEditorClass(String attrName) {
4008: return (Class) propertyEditorMaps.get(attrName);
4009: }
4010:
4011: /**
4012: * XXX
4013: */
4014: public Class getTagHandlerClass() {
4015: return tagHandlerClass;
4016: }
4017: }
4018:
4019: /**
4020: * A class for generating codes to a buffer. Included here are some support
4021: * for tracking source to Java lines mapping.
4022: */
4023: private static class GenBuffer {
4024:
4025: /*
4026: * For a CustomTag, the codes that are generated at the beginning of the
4027: * tag may not be in the same buffer as those for the body of the tag.
4028: * Two fields are used here to keep this straight. For codes that do not
4029: * corresponds to any JSP lines, they should be null.
4030: */
4031: private Node node;
4032:
4033: private Node.Nodes body;
4034:
4035: private java.io.CharArrayWriter charWriter;
4036:
4037: protected ServletWriter out;
4038:
4039: GenBuffer() {
4040: this (null, null);
4041: }
4042:
4043: GenBuffer(Node n, Node.Nodes b) {
4044: node = n;
4045: body = b;
4046: if (body != null) {
4047: body.setGeneratedInBuffer(true);
4048: }
4049: charWriter = new java.io.CharArrayWriter();
4050: out = new ServletWriter(new java.io.PrintWriter(charWriter));
4051: }
4052:
4053: public ServletWriter getOut() {
4054: return out;
4055: }
4056:
4057: public String toString() {
4058: return charWriter.toString();
4059: }
4060:
4061: /**
4062: * Adjust the Java Lines. This is necessary because the Java lines
4063: * stored with the nodes are relative the beginning of this buffer and
4064: * need to be adjusted when this buffer is inserted into the source.
4065: */
4066: public void adjustJavaLines(final int offset) {
4067:
4068: if (node != null) {
4069: adjustJavaLine(node, offset);
4070: }
4071:
4072: if (body != null) {
4073: try {
4074: body.visit(new Node.Visitor() {
4075:
4076: public void doVisit(Node n) {
4077: adjustJavaLine(n, offset);
4078: }
4079:
4080: public void visit(Node.CustomTag n)
4081: throws JasperException {
4082: Node.Nodes b = n.getBody();
4083: if (b != null && !b.isGeneratedInBuffer()) {
4084: // Don't adjust lines for the nested tags that
4085: // are also generated in buffers, because the
4086: // adjustments will be done elsewhere.
4087: b.visit(this );
4088: }
4089: }
4090: });
4091: } catch (JasperException ex) {
4092: }
4093: }
4094: }
4095:
4096: private static void adjustJavaLine(Node n, int offset) {
4097: if (n.getBeginJavaLine() > 0) {
4098: n.setBeginJavaLine(n.getBeginJavaLine() + offset);
4099: n.setEndJavaLine(n.getEndJavaLine() + offset);
4100: }
4101: }
4102: }
4103:
4104: /**
4105: * Keeps track of the generated Fragment Helper Class
4106: */
4107: private static class FragmentHelperClass {
4108:
4109: private static class Fragment {
4110: private GenBuffer genBuffer;
4111:
4112: private int id;
4113:
4114: public Fragment(int id, Node node) {
4115: this .id = id;
4116: genBuffer = new GenBuffer(null, node.getBody());
4117: }
4118:
4119: public GenBuffer getGenBuffer() {
4120: return this .genBuffer;
4121: }
4122:
4123: public int getId() {
4124: return this .id;
4125: }
4126: }
4127:
4128: // True if the helper class should be generated.
4129: private boolean used = false;
4130:
4131: private ArrayList fragments = new ArrayList();
4132:
4133: private String className;
4134:
4135: // Buffer for entire helper class
4136: private GenBuffer classBuffer = new GenBuffer();
4137:
4138: public FragmentHelperClass(String className) {
4139: this .className = className;
4140: }
4141:
4142: public String getClassName() {
4143: return this .className;
4144: }
4145:
4146: public boolean isUsed() {
4147: return this .used;
4148: }
4149:
4150: public void generatePreamble() {
4151: ServletWriter out = this .classBuffer.getOut();
4152: out.println();
4153: out.pushIndent();
4154: // Note: cannot be static, as we need to reference things like
4155: // _jspx_meth_*
4156: out.printil("private class " + className);
4157: out.printil(" extends "
4158: + "org.apache.jasper.runtime.JspFragmentHelper");
4159: out.printil("{");
4160: out.pushIndent();
4161: out
4162: .printil("private javax.servlet.jsp.tagext.JspTag _jspx_parent;");
4163: out.printil("private int[] _jspx_push_body_count;");
4164: out.println();
4165: out.printil("public " + className
4166: + "( int discriminator, JspContext jspContext, "
4167: + "javax.servlet.jsp.tagext.JspTag _jspx_parent, "
4168: + "int[] _jspx_push_body_count ) {");
4169: out.pushIndent();
4170: out
4171: .printil("super( discriminator, jspContext, _jspx_parent );");
4172: out.printil("this._jspx_parent = _jspx_parent;");
4173: out
4174: .printil("this._jspx_push_body_count = _jspx_push_body_count;");
4175: out.popIndent();
4176: out.printil("}");
4177: }
4178:
4179: public Fragment openFragment(Node parent, String tagHandlerVar,
4180: int methodNesting) throws JasperException {
4181: Fragment result = new Fragment(fragments.size(), parent);
4182: fragments.add(result);
4183: this .used = true;
4184: parent.setInnerClassName(className);
4185:
4186: ServletWriter out = result.getGenBuffer().getOut();
4187: out.pushIndent();
4188: out.pushIndent();
4189: // XXX - Returns boolean because if a tag is invoked from
4190: // within this fragment, the Generator sometimes might
4191: // generate code like "return true". This is ignored for now,
4192: // meaning only the fragment is skipped. The JSR-152
4193: // expert group is currently discussing what to do in this case.
4194: // See comment in closeFragment()
4195: if (methodNesting > 0) {
4196: out.printin("public boolean invoke");
4197: } else {
4198: out.printin("public void invoke");
4199: }
4200: out.println(result.getId() + "( " + "JspWriter out ) ");
4201: out.pushIndent();
4202: // Note: Throwable required because methods like _jspx_meth_*
4203: // throw Throwable.
4204: out.printil("throws Throwable");
4205: out.popIndent();
4206: out.printil("{");
4207: out.pushIndent();
4208: generateLocalVariables(out, parent);
4209:
4210: return result;
4211: }
4212:
4213: public void closeFragment(Fragment fragment, int methodNesting) {
4214: ServletWriter out = fragment.getGenBuffer().getOut();
4215: // XXX - See comment in openFragment()
4216: if (methodNesting > 0) {
4217: out.printil("return false;");
4218: } else {
4219: out.printil("return;");
4220: }
4221: out.popIndent();
4222: out.printil("}");
4223: }
4224:
4225: public void generatePostamble() {
4226: ServletWriter out = this .classBuffer.getOut();
4227: // Generate all fragment methods:
4228: for (int i = 0; i < fragments.size(); i++) {
4229: Fragment fragment = (Fragment) fragments.get(i);
4230: fragment.getGenBuffer().adjustJavaLines(
4231: out.getJavaLine() - 1);
4232: out.printMultiLn(fragment.getGenBuffer().toString());
4233: }
4234:
4235: // Generate postamble:
4236: out.printil("public void invoke( java.io.Writer writer )");
4237: out.pushIndent();
4238: out.printil("throws JspException");
4239: out.popIndent();
4240: out.printil("{");
4241: out.pushIndent();
4242: out.printil("JspWriter out = null;");
4243: out.printil("if( writer != null ) {");
4244: out.pushIndent();
4245: out.printil("out = this.jspContext.pushBody(writer);");
4246: out.popIndent();
4247: out.printil("} else {");
4248: out.pushIndent();
4249: out.printil("out = this.jspContext.getOut();");
4250: out.popIndent();
4251: out.printil("}");
4252: out.printil("try {");
4253: out.pushIndent();
4254: out
4255: .printil("this.jspContext.getELContext().putContext(JspContext.class,this.jspContext);");
4256: out.printil("switch( this.discriminator ) {");
4257: out.pushIndent();
4258: for (int i = 0; i < fragments.size(); i++) {
4259: out.printil("case " + i + ":");
4260: out.pushIndent();
4261: out.printil("invoke" + i + "( out );");
4262: out.printil("break;");
4263: out.popIndent();
4264: }
4265: out.popIndent();
4266: out.printil("}"); // switch
4267: out.popIndent();
4268: out.printil("}"); // try
4269: out.printil("catch( Throwable e ) {");
4270: out.pushIndent();
4271: out.printil("if (e instanceof SkipPageException)");
4272: out.printil(" throw (SkipPageException) e;");
4273: out.printil("throw new JspException( e );");
4274: out.popIndent();
4275: out.printil("}"); // catch
4276: out.printil("finally {");
4277: out.pushIndent();
4278:
4279: out.printil("if( writer != null ) {");
4280: out.pushIndent();
4281: out.printil("this.jspContext.popBody();");
4282: out.popIndent();
4283: out.printil("}");
4284:
4285: out.popIndent();
4286: out.printil("}"); // finally
4287: out.popIndent();
4288: out.printil("}"); // invoke method
4289: out.popIndent();
4290: out.printil("}"); // helper class
4291: out.popIndent();
4292: }
4293:
4294: public String toString() {
4295: return classBuffer.toString();
4296: }
4297:
4298: public void adjustJavaLines(int offset) {
4299: for (int i = 0; i < fragments.size(); i++) {
4300: Fragment fragment = (Fragment) fragments.get(i);
4301: fragment.getGenBuffer().adjustJavaLines(offset);
4302: }
4303: }
4304: }
4305: }
|