0001: /*
0002: * The Apache Software License, Version 1.1
0003: *
0004: * Copyright (c) 1999 The Apache Software Foundation. All rights
0005: * reserved.
0006: *
0007: * Redistribution and use in source and binary forms, with or without
0008: * modification, are permitted provided that the following conditions
0009: * are met:
0010: *
0011: * 1. Redistributions of source code must retain the above copyright
0012: * notice, this list of conditions and the following disclaimer.
0013: *
0014: * 2. Redistributions in binary form must reproduce the above copyright
0015: * notice, this list of conditions and the following disclaimer in
0016: * the documentation and/or other materials provided with the
0017: * distribution.
0018: *
0019: * 3. The end-user documentation included with the redistribution, if
0020: * any, must include the following acknowlegement:
0021: * "This product includes software developed by the
0022: * Apache Software Foundation (http://www.apache.org/)."
0023: * Alternately, this acknowlegement may appear in the software itself,
0024: * if and wherever such third-party acknowlegements normally appear.
0025: *
0026: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
0027: * Foundation" must not be used to endorse or promote products derived
0028: * from this software without prior written permission. For written
0029: * permission, please contact apache@apache.org.
0030: *
0031: * 5. Products derived from this software may not be called "Apache"
0032: * nor may "Apache" appear in their names without prior written
0033: * permission of the Apache Group.
0034: *
0035: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0046: * SUCH DAMAGE.
0047: * ====================================================================
0048: *
0049: * This software consists of voluntary contributions made by many
0050: * individuals on behalf of the Apache Software Foundation. For more
0051: * information on the Apache Software Foundation, please see
0052: * <http://www.apache.org/>.
0053: *
0054: */
0055: package com.rimfaxe.webserver.compiler.jsp;
0056:
0057: import java.util.*;
0058: import java.beans.*;
0059: import java.net.URLEncoder;
0060: import java.io.ByteArrayOutputStream;
0061: import java.io.PrintStream;
0062: import java.lang.reflect.Method;
0063: import javax.servlet.jsp.tagext.*;
0064: import org.xml.sax.Attributes;
0065:
0066: import com.rimfaxe.webserver.runtime.JspRuntimeLibrary;
0067: import com.rimfaxe.webserver.WebContext;
0068: import com.rimfaxe.webserver.compiler.JspToJavaException;
0069:
0070: /**
0071: * Generate Java source from Nodes
0072: *
0073: * @author Anil K. Vijendran
0074: * @author Danno Ferrin
0075: * @author Mandar Raje
0076: * @author Rajiv Mordani
0077: * @author Pierre Delisle
0078: * @author Kin-man Chung
0079: * @author Jan Luehe
0080: * @author Denis Benoit
0081: * @author Lars Andersen
0082: */
0083:
0084: public class Generator {
0085:
0086: private ServletWriter out;
0087: private MethodsBuffer methodsBuffer;
0088:
0089: private BeanRepository beanInfo;
0090:
0091: private boolean breakAtLF = true;
0092: private PageInfo pageInfo;
0093: private int maxTagNesting;
0094: private Vector tagHandlerPoolNames;
0095: private JspC compiler;
0096: private WebContext ctxt;
0097:
0098: /**
0099: * @param s the input string
0100: * @return quoted and escaped string, per Java rule
0101: */
0102: private static String quote(String s) {
0103:
0104: if (s == null)
0105: return "null";
0106:
0107: StringBuffer b = new StringBuffer();
0108: b.append('"');
0109: for (int i = 0; i < s.length(); i++) {
0110: char c = s.charAt(i);
0111: if (c == '"')
0112: b.append('\\').append('"');
0113: else if (c == '\\')
0114: b.append('\\').append('\\');
0115: else if (c == '\n')
0116: b.append('\\').append('n');
0117: else if (c == '\r')
0118: b.append('\\').append('r');
0119: else
0120: b.append(c);
0121: }
0122: b.append('"');
0123: return b.toString();
0124: }
0125:
0126: /**
0127: * Generates declarations. This includes "info" of the page directive,
0128: * and scriptlet declarations.
0129: */
0130: private void generateDeclarations(Node.Nodes page)
0131: throws JasperException, JspToJavaException {
0132:
0133: class DeclarationVisitor extends Node.Visitor {
0134:
0135: public void visit(Node.PageDirective n)
0136: throws JasperException {
0137: String info = n.getAttributeValue("info");
0138: if (info == null)
0139: return;
0140:
0141: out.printil("public String getServletInfo() {");
0142: out.pushIndent();
0143: out.printin("return ");
0144: out.print(quote(info));
0145: out.println(";");
0146: out.popIndent();
0147: out.print('}');
0148: out.println();
0149: }
0150:
0151: public void visit(Node.Declaration n)
0152: throws JasperException {
0153: out.printMultiLn(new String(n.getText()));
0154: }
0155: }
0156:
0157: out.println();
0158: page.visit(new DeclarationVisitor());
0159: }
0160:
0161: /**
0162: * Compiles list of tag handler pool names.
0163: */
0164: private void compileTagHandlerPoolList(Node.Nodes page)
0165: throws JasperException, JspToJavaException {
0166:
0167: class TagHandlerPoolVisitor extends Node.Visitor {
0168:
0169: private Vector names;
0170:
0171: /*
0172: * Constructor
0173: *
0174: * @param v Vector of tag handler pool names to populate
0175: */
0176: TagHandlerPoolVisitor(Vector v) {
0177: names = v;
0178: }
0179:
0180: /*
0181: * Gets the name of the tag handler pool for the given custom tag
0182: * and adds it to the list of tag handler pool names unless it is
0183: * already contained in it.
0184: */
0185: public void visit(Node.CustomTag n) throws JasperException,
0186: JspToJavaException {
0187:
0188: String name = createTagHandlerPoolName(n.getPrefix(), n
0189: .getShortName(), n.getAttributes());
0190: n.setTagHandlerPoolName(name);
0191: if (!names.contains(name)) {
0192: names.add(name);
0193: }
0194:
0195: visitBody(n);
0196: }
0197:
0198: /*
0199: * Creates the name of the tag handler pool whose tag handlers may
0200: * be (re)used to service this action.
0201: *
0202: * @return The name of the tag handler pool
0203: */
0204: private String createTagHandlerPoolName(String prefix,
0205: String shortName, Attributes attrs) {
0206: String poolName = null;
0207:
0208: if (prefix.indexOf('-') >= 0)
0209: prefix = JspUtil.replace(prefix, '-', "$1");
0210: if (prefix.indexOf('.') >= 0)
0211: prefix = JspUtil.replace(prefix, '.', "$2");
0212:
0213: if (shortName.indexOf('-') >= 0)
0214: shortName = JspUtil.replace(shortName, '-', "$1");
0215: if (shortName.indexOf('.') >= 0)
0216: shortName = JspUtil.replace(shortName, '.', "$2");
0217: if (shortName.indexOf(':') >= 0)
0218: shortName = JspUtil.replace(shortName, ':', "$3");
0219:
0220: poolName = "_jspx_tagPool_" + prefix + "_" + shortName;
0221: if (attrs != null) {
0222: String[] attrNames = new String[attrs.getLength()];
0223: for (int i = 0; i < attrNames.length; i++) {
0224: attrNames[i] = attrs.getQName(i);
0225: }
0226: Arrays.sort(attrNames, Collections.reverseOrder());
0227: for (int i = 0; i < attrNames.length; i++) {
0228: poolName = poolName + "_" + attrNames[i];
0229: }
0230: }
0231: return poolName;
0232: }
0233: }
0234:
0235: page.visit(new TagHandlerPoolVisitor(tagHandlerPoolNames));
0236: }
0237:
0238: /*
0239: * For every custom tag, declares its scripting variables with AT_BEGIN
0240: * and AT_END scopes.
0241: */
0242: private void declareAtBeginAtEndScriptingVariables(Node.Nodes page)
0243: throws JasperException, JspToJavaException {
0244:
0245: class ScriptingVariableDeclarationVisitor extends Node.Visitor {
0246:
0247: /*
0248: * Vector keeping track of which scripting variables have already
0249: * been declared
0250: */
0251: private Vector scriptVars;
0252:
0253: /*
0254: * Constructor.
0255: */
0256: public ScriptingVariableDeclarationVisitor() {
0257: scriptVars = new Vector();
0258: }
0259:
0260: public void visit(Node.CustomTag n) throws JasperException,
0261: JspToJavaException {
0262:
0263: TagVariableInfo[] tagVarInfos = n.getTagVariableInfos();
0264: VariableInfo[] varInfos = n.getVariableInfos();
0265:
0266: if ((varInfos == null) && (tagVarInfos == null)) {
0267:
0268: visitBody(n);
0269: }
0270:
0271: if (varInfos != null) {
0272: for (int i = 0; i < varInfos.length; i++) {
0273: int scope = varInfos[i].getScope();
0274: String varName = varInfos[i].getVarName();
0275: if (((scope == VariableInfo.AT_BEGIN) || (scope == VariableInfo.AT_END))
0276: && varInfos[i].getDeclare()
0277: && !scriptVars.contains(varName)) {
0278: out.printin(varInfos[i].getClassName());
0279: out.print(" ");
0280: out.print(varName);
0281: out.println(" = null;");
0282: scriptVars.add(varName);
0283: }
0284: }
0285: } else {
0286: //System.out.println("Generator. a");
0287: if (tagVarInfos != null) {
0288: for (int i = 0; i < tagVarInfos.length; i++) {
0289: //System.out.println("Generator. b");
0290: int scope = tagVarInfos[i].getScope();
0291: String varName = tagVarInfos[i]
0292: .getNameGiven();
0293: if (varName == null) {
0294: varName = n
0295: .getTagData()
0296: .getAttributeString(
0297: tagVarInfos[i]
0298: .getNameFromAttribute());
0299: }
0300: if (((scope == VariableInfo.AT_BEGIN) || (scope == VariableInfo.AT_END))
0301: && tagVarInfos[i].getDeclare()
0302: && !scriptVars.contains(varName)) {
0303: out.printin(tagVarInfos[i]
0304: .getClassName());
0305: out.print(" ");
0306: out.print(varName);
0307: out.println(" = null;");
0308: scriptVars.add(varName);
0309: }
0310: }
0311: }
0312: }
0313:
0314: //System.out.println("Generator. 1");
0315: visitBody(n);
0316: }
0317: }
0318:
0319: page.visit(new ScriptingVariableDeclarationVisitor());
0320: }
0321:
0322: /**
0323: * Generates the destroy() method which is responsible for calling the
0324: * release() method on every tag handler in any of the tag handler pools.
0325: */
0326: private void generateDestroy() {
0327: out.printil("public void jspDestroy() {");
0328: out.pushIndent();
0329: for (int i = 0; i < tagHandlerPoolNames.size(); i++) {
0330: out.printin((String) tagHandlerPoolNames.elementAt(i));
0331: out.println(".release();");
0332: }
0333: out.popIndent();
0334: out.printil("}");
0335: out.println();
0336: }
0337:
0338: /**
0339: * Generates the beginning of the static portion of the servlet.
0340: */
0341: private void generatePreamble(Node.Nodes page)
0342: throws JasperException, JspToJavaException {
0343:
0344: String servletPackageName = compiler.getServletPackageName();
0345: String servletClassName = compiler.getServletClassName();
0346: String serviceMethodName = Constants.SERVICE_METHOD_NAME;
0347:
0348: // First the package name:
0349:
0350: if (!"".equals(servletPackageName)
0351: && servletPackageName != null) {
0352: out.printil("package " + servletPackageName + ";");
0353: out.println();
0354: }
0355:
0356: // Generate imports
0357:
0358: Iterator iter = pageInfo.getImports().iterator();
0359: while (iter.hasNext()) {
0360: out.printin("import ");
0361: out.print((String) iter.next());
0362: out.println(";");
0363: }
0364: out.println();
0365:
0366: // Generate class declaration
0367:
0368: out.printin("public class ");
0369: out.print(servletClassName);
0370: out.print(" extends ");
0371: out.print(pageInfo.getExtends());
0372: if (!pageInfo.isThreadSafe()) {
0373: out.print("implements SingleThreadModel");
0374: }
0375: out.println(" {");
0376: out.pushIndent();
0377:
0378: // Class body begins here
0379:
0380: generateDeclarations(page);
0381: out.println();
0382:
0383: // Static initializations here
0384:
0385: // Static data for getIncludes()
0386: out.printil("private static java.util.Vector _jspx_includes;");
0387: out.println();
0388: List includes = pageInfo.getIncludes();
0389: iter = includes.iterator();
0390: if (!includes.isEmpty()) {
0391: out.printil("static {");
0392: out.pushIndent();
0393: out.printin("_jspx_includes = new java.util.Vector(");
0394: out.print("" + includes.size());
0395: out.println(");");
0396: while (iter.hasNext()) {
0397: out.printin("_jspx_includes.add(\"");
0398: out.print((String) iter.next());
0399: out.println("\");");
0400: }
0401: out.popIndent();
0402: out.printil("}");
0403: out.println();
0404: }
0405:
0406: // Class variable declarations
0407:
0408: /*
0409: * Declare tag handler pools (tags of the same type and with the same
0410: * attribute set share the same tag handler pool)
0411: */
0412: /*if (ctxt.getOptions().isPoolingEnabled()
0413: && !tagHandlerPoolNames.isEmpty()) {
0414: for (int i=0; i<tagHandlerPoolNames.size(); i++) {
0415: out.printil("private org.apache.jasper.runtime.TagHandlerPool "
0416: + tagHandlerPoolNames.elementAt(i) + ";");
0417: }
0418: out.println();
0419: }*/
0420:
0421: // Constructor
0422: /*if (ctxt.getOptions().isPoolingEnabled()
0423: && !tagHandlerPoolNames.isEmpty()) {
0424: generateServletConstructor(servletClassName);
0425: }*/
0426:
0427: // Methods here
0428: // Method used to get compile time include file dependencies
0429: out.printil("public java.util.List getIncludes() {");
0430: out.pushIndent();
0431: out.printil("return _jspx_includes;");
0432: out.popIndent();
0433: out.printil("}");
0434: out.println();
0435:
0436: /*if (ctxt.getOptions().isPoolingEnabled()
0437: && !tagHandlerPoolNames.isEmpty()) {
0438: generateDestroy();
0439: }*/
0440:
0441: // Now the service method
0442: out.printin("public void ");
0443: out.print(serviceMethodName);
0444: out
0445: .println("(HttpServletRequest request, HttpServletResponse response)");
0446: out
0447: .println(" throws java.io.IOException, ServletException {");
0448:
0449: out.pushIndent();
0450: out.println();
0451:
0452: // Local variable declarations
0453: out.printil("JspFactory _jspxFactory = null;");
0454: out
0455: .printil("javax.servlet.jsp.PageContext pageContext = null;");
0456: if (pageInfo.isSession())
0457: out.printil("HttpSession session = null;");
0458:
0459: if (pageInfo.isIsErrorPage())
0460: out
0461: .printil("Throwable exception = (Throwable) request.getAttribute(\"javax.servlet.jsp.jspException\");");
0462:
0463: out.printil("ServletContext application = null;");
0464: out.printil("ServletConfig config = null;");
0465: out.printil("JspWriter out = null;");
0466: out.printil("Object page = this;");
0467:
0468: // Number of tag object that need to be popped
0469: // XXX TODO: use a better criteria
0470: maxTagNesting = pageInfo.getMaxTagNesting();
0471: /*
0472: if (maxTagNesting > 0) {
0473: out.printil("JspxState _jspxState = new JspxState();");
0474: }
0475: */
0476: out.printil("JspWriter _jspx_out = null;");
0477: out.println();
0478:
0479: declareAtBeginAtEndScriptingVariables(page);
0480: out.println();
0481:
0482: out.printil("try {");
0483: out.pushIndent();
0484:
0485: out.printil("_jspxFactory = JspFactory.getDefaultFactory();");
0486:
0487: out.printin("response.setContentType(");
0488: out.print(quote(pageInfo.getContentType()));
0489: out.println(");");
0490:
0491: out
0492: .printil("pageContext = _jspxFactory.getPageContext(this, request, response,");
0493: out.printin("\t\t\t");
0494: out.print(quote(pageInfo.getErrorPage()));
0495: out.print(", " + pageInfo.isSession());
0496: out.print(", " + pageInfo.getBuffer());
0497: out.print(", " + pageInfo.isAutoFlush());
0498: out.println(");");
0499:
0500: out.printil("application = pageContext.getServletContext();");
0501: out.printil("config = pageContext.getServletConfig();");
0502:
0503: if (pageInfo.isSession())
0504: out.printil("session = pageContext.getSession();");
0505: out.printil("out = pageContext.getOut();");
0506: out.printil("_jspx_out = out;");
0507: out.println();
0508: }
0509:
0510: /*
0511: * Generates the servlet constructor.
0512: */
0513: private void generateServletConstructor(String servletClassName) {
0514: out.printil("public " + servletClassName + "() {");
0515: out.pushIndent();
0516: for (int i = 0; i < tagHandlerPoolNames.size(); i++) {
0517: out.printin((String) tagHandlerPoolNames.elementAt(i));
0518: out
0519: .println(" = new com.rimfaxe.webserver.runtime.TagHandlerPool();");
0520: }
0521: out.popIndent();
0522: out.printil("}");
0523: out.println();
0524: }
0525:
0526: /**
0527: * Generate codes defining the classes used in the servlet.
0528: * 1. Servlet state object, used to pass servlet info round methods.
0529: */
0530: private void generateJspState() {
0531: /*
0532: out.println();
0533: out.printil("static final class JspxState {");
0534: out.pushIndent();
0535: out.printil("public JspWriter out;");
0536: out.println();
0537: out.printil("public JspxState() {");
0538: out.pushIndent();
0539: out.popIndent();
0540: out.printil("}");
0541: out.popIndent();
0542: out.printil("}");
0543: */
0544: }
0545:
0546: /**
0547: * A visitor that generates codes for the elements in the page.
0548: */
0549: class GenerateVisitor extends Node.Visitor {
0550:
0551: /*
0552: * Hashtable containing introspection information on tag handlers:
0553: * <key>: tag prefix
0554: * <value>: hashtable containing introspection on tag handlers:
0555: * <key>: tag short name
0556: * <value>: introspection info of tag handler for
0557: * <prefix:shortName> tag
0558: */
0559: private Hashtable handlerInfos;
0560:
0561: private Hashtable tagVarNumbers;
0562: private String parent;
0563:
0564: private ServletWriter out;
0565: private MethodsBuffer methodsBuffer;
0566: private int methodNesting;
0567:
0568: /**
0569: * Constructor.
0570: */
0571: public GenerateVisitor(ServletWriter out,
0572: MethodsBuffer methodsBuffer) {
0573: this .out = out;
0574: this .methodsBuffer = methodsBuffer;
0575: methodNesting = 0;
0576: handlerInfos = new Hashtable();
0577: tagVarNumbers = new Hashtable();
0578: }
0579:
0580: /**
0581: * Returns an attribute value, optionally URL encoded. If
0582: * the value is a runtime expression, the result is the string for
0583: * the expression, otherwise the result is the string literal,
0584: * quoted and escaped.
0585: * @param attr An JspAttribute object
0586: * @param encode true if to be URL encoded
0587: */
0588: public String attributeValue(Node.JspAttribute attr,
0589: boolean encode) {
0590: String v = attr.getValue();
0591: if (v == null)
0592: return "";
0593:
0594: if (attr.isExpression()) {
0595: if (encode) {
0596: return "java.net.URLEncoder.encode(" + v + ")";
0597: }
0598: return v;
0599: } else {
0600: if (encode) {
0601: v = URLEncoder.encode(v);
0602: }
0603: return quote(v);
0604: }
0605: }
0606:
0607: /**
0608: * Prints the attribute value specified in the param action, in the
0609: * form of name=value string.
0610: *
0611: * @param n the parent node for the param action nodes.
0612: */
0613: public void printParams(Node n, Node.JspAttribute page)
0614: throws JasperException, JspToJavaException {
0615:
0616: String pValue = page.getValue();
0617: String sep;
0618: if (page.isExpression()) {
0619: sep = "((" + pValue + ").indexOf('?')>0? '&': '?')";
0620: } else {
0621: sep = pValue.indexOf('?') > 0 ? "\"&\"" : "\"?\"";
0622: }
0623: if (n.getBody() != null) {
0624: n
0625: .getBody()
0626: .visit(
0627: new com.rimfaxe.webserver.compiler.jsp.ParamVisitor(
0628: sep, out, this ));
0629: }
0630: }
0631:
0632: public void visit(Node.Expression n) throws JasperException,
0633: JspToJavaException {
0634: n.setBeginJavaLine(out.getJavaLine());
0635: out.printil("out.print(" + new String(n.getText()) + ");");
0636: n.setEndJavaLine(out.getJavaLine());
0637: }
0638:
0639: public void visit(Node.Scriptlet n) throws JasperException,
0640: JspToJavaException {
0641: n.setBeginJavaLine(out.getJavaLine());
0642: out.printMultiLn(new String(n.getText()));
0643: n.setEndJavaLine(out.getJavaLine());
0644: }
0645:
0646: public void visit(Node.IncludeAction n) throws JasperException,
0647: JspToJavaException {
0648:
0649: String flush = n.getAttributeValue("flush");
0650:
0651: boolean isFlush = false; // default to false;
0652: if ("true".equals(flush))
0653: isFlush = true;
0654:
0655: n.setBeginJavaLine(out.getJavaLine());
0656:
0657: out
0658: .printin("JspRuntimeLibrary.include(request, response, ");
0659: out.print(attributeValue(n.getPage(), false));
0660: printParams(n, n.getPage());
0661: out.println(", out, " + isFlush + ");");
0662:
0663: n.setEndJavaLine(out.getJavaLine());
0664: }
0665:
0666: public void visit(Node.ForwardAction n) throws JasperException,
0667: JspToJavaException {
0668: String page = n.getAttributeValue("page");
0669:
0670: n.setBeginJavaLine(out.getJavaLine());
0671:
0672: out.printil("if (true) {"); // So that javac won't complain about
0673: out.pushIndent(); // codes after "return"
0674: out.printin("pageContext.forward(");
0675: out.print(attributeValue(n.getPage(), false));
0676: printParams(n, n.getPage());
0677: out.println(");");
0678: out.printil((methodNesting > 0) ? "return true;"
0679: : "return;");
0680: out.popIndent();
0681: out.printil("}");
0682:
0683: n.setEndJavaLine(out.getJavaLine());
0684: // XXX Not sure if we can eliminate dead codes after this.
0685: }
0686:
0687: public void visit(Node.GetProperty n) throws JasperException,
0688: JspToJavaException {
0689: String name = n.getAttributeValue("name");
0690: String property = n.getAttributeValue("property");
0691:
0692: n.setBeginJavaLine(out.getJavaLine());
0693:
0694: if (beanInfo.checkVariable(name)) {
0695: // Bean is defined using useBean, introspect at compile time
0696: Class bean = beanInfo.getBeanType(name);
0697: String beanName = bean.getName();
0698: java.lang.reflect.Method meth = JspRuntimeLibrary
0699: .getReadMethod(bean, property);
0700: String methodName = meth.getName();
0701: out.printil("out.print(JspRuntimeLibrary.toString("
0702: + "(((" + beanName
0703: + ")pageContext.findAttribute(" + "\"" + name
0704: + "\"))." + methodName + "())));");
0705: } else {
0706: // The object could be a custom action with an associated
0707: // VariableInfo entry for this name.
0708: // Get the class name and then introspect at runtime.
0709: out.printil("out.print(JspRuntimeLibrary.toString"
0710: + "(JspRuntimeLibrary.handleGetProperty"
0711: + "(pageContext.findAttribute(\"" + name
0712: + "\"), \"" + property + "\")));");
0713: }
0714:
0715: n.setEndJavaLine(out.getJavaLine());
0716: }
0717:
0718: public void visit(Node.SetProperty n) throws JasperException,
0719: JspToJavaException {
0720: String name = n.getAttributeValue("name");
0721: String property = n.getAttributeValue("property");
0722: String param = n.getAttributeValue("param");
0723: Node.JspAttribute value = n.getValue();
0724:
0725: n.setBeginJavaLine(out.getJavaLine());
0726:
0727: if ("*".equals(property)) {
0728: out
0729: .printil("com.rimfaxe.webserver.runtime.JspRuntimeLibrary.introspect("
0730: + "pageContext.findAttribute("
0731: + "\""
0732: + name + "\"), request);");
0733: } else if (value == null) {
0734: if (param == null)
0735: param = property; // default to same as property
0736: out
0737: .printil("com.rimfaxe.webserver.runtime.JspRuntimeLibrary.introspecthelper("
0738: + "pageContext.findAttribute(\""
0739: + name
0740: + "\"), \""
0741: + property
0742: + "\", request.getParameter(\""
0743: + param
0744: + "\"), "
0745: + "request, \""
0746: + param
0747: + "\", false);");
0748: } else if (value.isExpression()) {
0749: out
0750: .printil("com.rimfaxe.webserver.runtime.JspRuntimeLibrary.handleSetProperty("
0751: + "pageContext.findAttribute(\""
0752: + name
0753: + "\"), \"" + property + "\",");
0754: out.print(attributeValue(value, false));
0755: out.println(");");
0756: } else {
0757: out
0758: .printil("com.rimfaxe.webserver.runtime.JspRuntimeLibrary.introspecthelper("
0759: + "pageContext.findAttribute(\""
0760: + name
0761: + "\"), \"" + property + "\",");
0762: out.print(attributeValue(value, false));
0763: out.println(",null, null, false);");
0764: }
0765:
0766: n.setEndJavaLine(out.getJavaLine());
0767: }
0768:
0769: public void visit(Node.UseBean n) throws JasperException,
0770: JspToJavaException {
0771:
0772: String name = n.getAttributeValue("id");
0773: String scope = n.getAttributeValue("scope");
0774: String klass = n.getAttributeValue("class");
0775: String type = n.getAttributeValue("type");
0776: Node.JspAttribute beanName = n.getBeanName();
0777:
0778: if (type == null) // if unspecified, use class as type of bean
0779: type = klass;
0780:
0781: String scopename = "PageContext.PAGE_SCOPE"; // Default to page
0782: String lock = "pageContext";
0783:
0784: if ("request".equals(scope)) {
0785: scopename = "PageContext.REQUEST_SCOPE";
0786: lock = "request";
0787: } else if ("session".equals(scope)) {
0788: scopename = "PageContext.SESSION_SCOPE";
0789: lock = "session";
0790: } else if ("application".equals(scope)) {
0791: scopename = "PageContext.APPLICATION_SCOPE";
0792: lock = "application";
0793: }
0794:
0795: n.setBeginJavaLine(out.getJavaLine());
0796:
0797: // Declare bean
0798: out.printin(type);
0799: out.print(' ');
0800: out.print(name);
0801: out.println(" = null;");
0802:
0803: // Lock while getting or creating bean
0804: out.printin("synchronized (");
0805: out.print(lock);
0806: out.println(") {");
0807: out.pushIndent();
0808:
0809: // Locate bean from context
0810: out.printin(name);
0811: out.print(" = (");
0812: out.print(type);
0813: out.print(") pageContext.getAttribute(");
0814: out.print(quote(name));
0815: out.print(", ");
0816: out.print(scopename);
0817: out.println(");");
0818:
0819: // Create bean
0820: /*
0821: * Check if bean is alredy there
0822: */
0823: out.printin("if (");
0824: out.print(name);
0825: out.println(" == null){");
0826: out.pushIndent();
0827: if (klass == null && beanName == null) {
0828: /*
0829: * If both class name and beanName is not specified, the bean
0830: * must be found locally, otherwise it's an error
0831: */
0832: out
0833: .printin("throw new java.lang.InstantiationException(\"bean ");
0834: out.print(name);
0835: out.println(" not found within scope\");");
0836: } else {
0837: /*
0838: * Instantiate bean if not there
0839: */
0840: String className;
0841: if (beanName != null) {
0842: className = attributeValue(beanName, false);
0843: } else {
0844: // Implies klass is not null
0845: className = quote(klass);
0846: }
0847:
0848: /*out.pushIndent();
0849: out.printin(name);
0850: out.print (" = ");
0851:
0852: out.print (" new "+klass+"();");
0853: out.popIndent();
0854: out.printil("");*/
0855:
0856: out.printil("try {");
0857: out.pushIndent();
0858: out.printin(name);
0859: out.print(" = (");
0860: out.print(type);
0861: out.print(") java.beans.Beans.instantiate(");
0862: out.print("this.getClass().getClassLoader(), ");
0863:
0864: out.print(className);
0865: out.println(");");
0866: out.popIndent();
0867:
0868: out.printil("} catch (ClassNotFoundException exc) {");
0869: out.pushIndent();
0870: out
0871: .printil("throw new InstantiationException(exc.getMessage());");
0872: out.popIndent();
0873: out.printil("} catch (Exception exc) {");
0874: out.pushIndent();
0875: out.printin("throw new ServletException(");
0876: out.print("\"Cannot create bean of class \" + ");
0877: out.print(className);
0878: out.println(", exc);");
0879: out.popIndent();
0880: out.printil("}"); // close of try
0881:
0882: /*
0883: * Set attribute for bean in the specified scope
0884: */
0885: out.printin("pageContext.setAttribute(");
0886: out.print(quote(name));
0887: out.print(", ");
0888: out.print(name);
0889: out.print(", ");
0890: out.print(scopename);
0891: out.println(");");
0892:
0893: // Only visit the body when bean is instantiated
0894: visitBody(n);
0895: }
0896: out.popIndent();
0897: out.printil("}");
0898:
0899: // End of lock block
0900: out.popIndent();
0901: out.printil("}");
0902:
0903: n.setEndJavaLine(out.getJavaLine());
0904: }
0905:
0906: /**
0907: * @return a string for the form 'attr = "value"'
0908: */
0909: private String makeAttr(String attr, String value) {
0910: if (value == null)
0911: return "";
0912:
0913: return " " + attr + "=\"" + value + '\"';
0914: }
0915:
0916: public void visit(Node.PlugIn n) throws JasperException,
0917: JspToJavaException {
0918:
0919: /**
0920: * A visitor to handle <jsp:param> in a plugin
0921: */
0922: class ParamVisitor extends Node.Visitor {
0923:
0924: private boolean ie;
0925:
0926: ParamVisitor(boolean ie) {
0927: this .ie = ie;
0928: }
0929:
0930: public void visit(Node.ParamAction n)
0931: throws JasperException {
0932:
0933: String name = n.getAttributeValue("name");
0934: if (name.equalsIgnoreCase("object"))
0935: name = "java_object";
0936: else if (name.equalsIgnoreCase("type"))
0937: name = "java_type";
0938:
0939: String s0 = makeAttr("name", name) + " value="
0940: + attributeValue(n.getValue(), false);
0941:
0942: if (ie) {
0943: s0 = "<PARAM" + s0 + '>';
0944: }
0945:
0946: n.setBeginJavaLine(out.getJavaLine());
0947: out.printil("out.println(" + quote(s0) + ");");
0948: n.setEndJavaLine(out.getJavaLine());
0949: }
0950: }
0951:
0952: String type = n.getAttributeValue("type");
0953: String code = n.getAttributeValue("code");
0954: String name = n.getAttributeValue("name");
0955: Node.JspAttribute height = n.getHeight();
0956: Node.JspAttribute width = n.getWidth();
0957: String hspace = n.getAttributeValue("hspace");
0958: String vspace = n.getAttributeValue("vspace");
0959: String align = n.getAttributeValue("align");
0960: String iepluginurl = n.getAttributeValue("iepluginurl");
0961: String nspluginurl = n.getAttributeValue("nspluginurl");
0962: String codebase = n.getAttributeValue("codebase");
0963: String archive = n.getAttributeValue("archive");
0964: String jreversion = n.getAttributeValue("jreversion");
0965:
0966: if (iepluginurl == null)
0967: iepluginurl = Constants.IE_PLUGIN_URL;
0968: if (nspluginurl == null)
0969: nspluginurl = Constants.NS_PLUGIN_URL;
0970:
0971: n.setBeginJavaLine(out.getJavaLine());
0972: // IE style plugin
0973: // <OBJECT ...>
0974: // First compose the runtime output string
0975: String s0 = "<OBJECT classid=\"" + compiler.getIeClassId()
0976: + "\"" + makeAttr("name", name);
0977: String s1, s2;
0978: if (width != null) {
0979: if (width.isExpression()) {
0980: s1 = quote(s0 + " width=\"") + " + "
0981: + width.getValue() + " + " + quote("\"");
0982: } else {
0983: s1 = quote(s0 + makeAttr("width", width.getValue()));
0984: }
0985: } else {
0986: s1 = quote(s0);
0987: }
0988: if (height != null) {
0989: if (height.isExpression()) {
0990: s2 = quote(" height=\"") + " + "
0991: + height.getValue() + " + " + quote("\"");
0992: } else {
0993: s2 = quote(makeAttr("height", height.getValue()));
0994: }
0995: } else {
0996: s2 = "\"\"";
0997: }
0998: String s3 = quote(makeAttr("hspace", hspace)
0999: + makeAttr("vspace", vspace)
1000: + makeAttr("align", align)
1001: + makeAttr("codebase", iepluginurl) + '>');
1002: // Then print the output string to the java file
1003: out.printil("out.println(" + s1 + " + " + s2 + " + " + s3
1004: + ");");
1005:
1006: // <PARAM > for java_code
1007: s0 = "<PARAM name=\"java_code\"" + makeAttr("value", code)
1008: + '>';
1009: out.printil("out.println(" + quote(s0) + ");");
1010:
1011: // <PARAM > for java_codebase
1012: if (codebase != null) {
1013: s0 = "<PARAM name=\"java_codebase\""
1014: + makeAttr("value", codebase) + '>';
1015: out.printil("out.println(" + quote(s0) + ");");
1016: }
1017:
1018: // <PARAM > for java_archive
1019: if (archive != null) {
1020: s0 = "<PARAM name=\"java_archive\""
1021: + makeAttr("value", archive) + '>';
1022: out.printil("out.println(" + quote(s0) + ");");
1023: }
1024:
1025: // <PARAM > for type
1026: s0 = "<PARAM name=\"type\""
1027: + makeAttr("value", "application/x-java-"
1028: + type
1029: + ";"
1030: + ((jreversion == null) ? "" : "version="
1031: + jreversion)) + '>';
1032: out.printil("out.println(" + quote(s0) + ");");
1033:
1034: /*
1035: * generate a <PARAM> for each <jsp:param> in the plugin body
1036: */
1037: if (n.getBody() != null)
1038: n.getBody().visit(new ParamVisitor(true));
1039:
1040: /*
1041: * Netscape style plugin part
1042: */
1043: out.printil("out.println(" + quote("<COMMENT>") + ");");
1044: s0 = "<EMBED"
1045: + makeAttr("type", "application/x-java-"
1046: + type
1047: + ";"
1048: + ((jreversion == null) ? "" : "version="
1049: + jreversion))
1050: + makeAttr("name", name);
1051:
1052: if (width != null) {
1053: if (width.isExpression()) {
1054: s1 = quote(s0 + " width=\"") + " + "
1055: + width.getValue() + " + " + quote("\"");
1056: } else {
1057: s1 = quote(s0 + makeAttr("width", width.getValue()));
1058: }
1059: } else {
1060: s1 = quote(s0);
1061: }
1062: if (height != null) {
1063: if (height.isExpression()) {
1064: s2 = quote(" height=\"") + " + "
1065: + height.getValue() + " + " + quote("\"");
1066: } else {
1067: s2 = quote(makeAttr("height", height.getValue()));
1068: }
1069: } else {
1070: s2 = "\"\"";
1071: }
1072:
1073: s3 = quote(makeAttr("hspace", hspace)
1074: + makeAttr("vspace", vspace)
1075: + makeAttr("align", align)
1076: + makeAttr("pluginspage", nspluginurl)
1077: + makeAttr("java_code", code)
1078: + makeAttr("java_codebase", codebase)
1079: + makeAttr("java_archive", archive));
1080: out.printil("out.println(" + s1 + " + " + s2 + " + " + s3
1081: + ");");
1082:
1083: /*
1084: * Generate a 'attr = "value"' for each <jsp:param> in plugin body
1085: */
1086: if (n.getBody() != null)
1087: n.getBody().visit(new ParamVisitor(false));
1088:
1089: out.printil("out.println(" + quote(">") + ");");
1090:
1091: out.printil("out.println(" + quote("<NOEMBED>") + ");");
1092: out.printil("out.println(" + quote("</COMMENT>") + ");");
1093:
1094: /*
1095: * Fallback
1096: */
1097: if (n.getBody() != null) {
1098: n.getBody().visit(new Node.Visitor() {
1099: public void visit(Node.FallBackAction n) {
1100: n.setBeginJavaLine(out.getJavaLine());
1101: out
1102: .printil("out.println("
1103: + quote(new String(n.getText()))
1104: + ");");
1105: n.setEndJavaLine(out.getJavaLine());
1106: }
1107: });
1108: }
1109:
1110: out.printil("out.println(" + quote("</NOEMBED></EMBED>")
1111: + ");");
1112: out.printil("out.println(" + quote("</OBJECT>") + ");");
1113:
1114: n.setEndJavaLine(out.getJavaLine());
1115: }
1116:
1117: public void visit(Node.CustomTag n) throws JasperException,
1118: JspToJavaException {
1119:
1120: Hashtable handlerInfosByShortName = (Hashtable) handlerInfos
1121: .get(n.getPrefix());
1122:
1123: if (handlerInfosByShortName == null) {
1124: handlerInfosByShortName = new Hashtable();
1125: handlerInfos
1126: .put(n.getPrefix(), handlerInfosByShortName);
1127: }
1128:
1129: TagHandlerInfo handlerInfo = (TagHandlerInfo) handlerInfosByShortName
1130: .get(n.getShortName());
1131:
1132: if (handlerInfo == null) {
1133:
1134: handlerInfo = new TagHandlerInfo(n, n.getTagInfo()
1135: .getTagClassName());
1136:
1137: //System.out.println("GenerateVisitor handlerInfo == null b");
1138: handlerInfosByShortName.put(n.getShortName(),
1139: handlerInfo);
1140: }
1141:
1142: // Create variable names
1143:
1144: String baseVar = createTagVarName(n.getName(), n
1145: .getPrefix(), n.getShortName());
1146: String tagEvalVar = "_jspx_eval_" + baseVar;
1147: String tagHandlerVar = "_jspx_th_" + baseVar;
1148:
1149: // If the tag contains no scripting element, generate its codes
1150: // to a method.
1151: ServletWriter outSave = null;
1152: MethodsBuffer methodsBufferSave = null;
1153: if (n.isScriptless() && !n.hasScriptingVars()) {
1154: // The tag handler and its body code can reside in a separate
1155: // method if it is scriptless and does not have any scripting
1156: // variable defined.
1157:
1158: String tagMethod = "_jspx_meth_" + baseVar;
1159:
1160: // Generate a call to this method
1161: out.printin("if (");
1162: out.print(tagMethod);
1163: out.print("(");
1164: if (parent != null) {
1165: out.print(parent);
1166: out.print(", ");
1167: }
1168: // out.println("pageContext, _jspxState)");
1169: out.println("pageContext))");
1170: out.pushIndent();
1171: out.printil((methodNesting > 0) ? "return true;"
1172: : "return;");
1173: out.popIndent();
1174:
1175: // Set up new buffer for the method
1176: outSave = out;
1177: out = methodsBuffer.getOut();
1178: methodsBufferSave = methodsBuffer;
1179: methodsBuffer = new MethodsBuffer();
1180:
1181: methodNesting++;
1182: // Generate code for method declaration
1183: out.println();
1184: out.pushIndent();
1185: out.printin("private boolean ");
1186: out.print(tagMethod);
1187: out.print("(");
1188: if (parent != null) {
1189: out.print("javax.servlet.jsp.tagext.Tag ");
1190: out.print(parent);
1191: out.print(", ");
1192: }
1193: // out.println("javax.servlet.jsp.PageContext pageContext, JspxState _jspxState)");
1194: out
1195: .println("javax.servlet.jsp.PageContext pageContext)");
1196: out.printil(" throws Throwable {");
1197: out.pushIndent();
1198:
1199: // Initilaize local variables used in this method.
1200: out.printil("JspWriter out = pageContext.getOut();");
1201: if (n.isHasUsebean()) {
1202: out
1203: .println("HttpSession session = pageContext.getSession();");
1204: out
1205: .println("ServletContext application = pageContext.getServletContext();");
1206: }
1207: if (n.isHasUsebean() || n.isHasIncludeAction()
1208: || n.isHasSetProperty()) {
1209: out
1210: .println("HttpServletRequest request = (HttpServletRequest)pageContext.getRequest();");
1211: }
1212: if (n.isHasIncludeAction()) {
1213: out
1214: .println("HttpServletResponse response = (HttpServletResponse)pageContext.getResponse();");
1215: }
1216: }
1217:
1218: Class tagHandlerClass = handlerInfo.getTagHandlerClass();
1219: boolean implements IterationTag = IterationTag.class
1220: .isAssignableFrom(tagHandlerClass);
1221: boolean implements BodyTag = BodyTag.class
1222: .isAssignableFrom(tagHandlerClass);
1223: boolean implements TryCatchFinally = TryCatchFinally.class
1224: .isAssignableFrom(tagHandlerClass);
1225:
1226: // Generate code for start tag, body, and end tag
1227: generateCustomStart(n, handlerInfo, tagHandlerVar,
1228: tagEvalVar, implements IterationTag,
1229: implements BodyTag, implements TryCatchFinally);
1230:
1231: String tmpParent = parent;
1232: parent = tagHandlerVar;
1233:
1234: visitBody(n);
1235:
1236: parent = tmpParent;
1237: generateCustomEnd(n, tagHandlerVar, tagEvalVar,
1238: implements IterationTag, implements BodyTag,
1239: implements TryCatchFinally);
1240:
1241: if (n.isScriptless() && !n.hasScriptingVars()) {
1242: // Generate end of method
1243: if (methodNesting > 0) {
1244: out.printil("return false;");
1245: }
1246: out.popIndent();
1247: out.printil("}");
1248: out.popIndent();
1249:
1250: methodNesting--;
1251:
1252: // Append any methods that got generated in the body to the
1253: // current buffer
1254: out.print(methodsBuffer.toString());
1255:
1256: // restore previous buffer
1257: methodsBuffer = methodsBufferSave;
1258: out = outSave;
1259: }
1260: }
1261:
1262: private static final String SINGLE_QUOTE = "'";
1263: private static final String DOUBLE_QUOTE = "\\\"";
1264:
1265: public void visit(Node.UninterpretedTag n)
1266: throws JasperException, JspToJavaException {
1267:
1268: /*
1269: * Write begin tag
1270: */
1271: out.printin("out.write(\"<");
1272: out.print(n.getName());
1273: Attributes attrs = n.getAttributes();
1274: if (attrs != null) {
1275: int attrsLength = attrs.getLength();
1276: for (int i = 0; i < attrsLength; i++) {
1277: String quote = DOUBLE_QUOTE;
1278: String value = attrs.getValue(i);
1279: if (value.indexOf('"') != -1) {
1280: quote = SINGLE_QUOTE;
1281: }
1282: out.print(" ");
1283: out.print(attrs.getQName(i));
1284: out.print("=");
1285: out.print(quote);
1286: out.print(value);
1287: out.print(quote);
1288: }
1289: }
1290:
1291: if (n.getBody() != null) {
1292: out.println(">\");");
1293:
1294: // Visit tag body
1295: visitBody(n);
1296:
1297: /*
1298: * Write end tag
1299: */
1300: out.printin("out.write(\"</");
1301: out.print(n.getName());
1302: out.println(">\");");
1303: } else {
1304: out.println("/>\");");
1305: }
1306: }
1307:
1308: private static final int CHUNKSIZE = 1024;
1309:
1310: public void visit(Node.TemplateText n) throws JasperException,
1311: JspToJavaException {
1312:
1313: char[] chars = n.getText();
1314: int size = chars.length;
1315:
1316: n.setBeginJavaLine(out.getJavaLine());
1317:
1318: out.printin();
1319: StringBuffer sb = new StringBuffer("out.write(\"");
1320: int initLength = sb.length();
1321: int count = CHUNKSIZE;
1322: for (int i = 0; i < size; i++) {
1323: char ch = chars[i];
1324: --count;
1325: switch (ch) {
1326: case '"':
1327: sb.append('\\').append('\"');
1328: break;
1329: case '\\':
1330: sb.append('\\').append('\\');
1331: break;
1332: case '\r':
1333: sb.append('\\').append('r');
1334: break;
1335: case '\n':
1336: sb.append('\\').append('n');
1337:
1338: if (breakAtLF || count < 0) {
1339: // Generate an out.write() when see a '\n' in template
1340: sb.append("\");");
1341: out.println(sb.toString());
1342: out.printin();
1343: sb.setLength(initLength);
1344: count = CHUNKSIZE;
1345: }
1346: break;
1347: case '\t': // Not sure we need this
1348: sb.append('\\').append('t');
1349: break;
1350: default:
1351: sb.append(ch);
1352: }
1353: }
1354:
1355: if (sb.length() > initLength) {
1356: sb.append("\");");
1357: out.println(sb.toString());
1358: }
1359:
1360: n.setEndJavaLine(out.getJavaLine());
1361: }
1362:
1363: private void generateCustomStart(Node.CustomTag n,
1364: TagHandlerInfo handlerInfo, String tagHandlerVar,
1365: String tagEvalVar, boolean implements IterationTag,
1366: boolean implements BodyTag,
1367: boolean implements TryCatchFinally)
1368: throws JasperException {
1369:
1370: Class tagHandlerClass = handlerInfo.getTagHandlerClass();
1371:
1372: n.setBeginJavaLine(out.getJavaLine());
1373: out.printin("/* ---- ");
1374: out.print(n.getName());
1375: out.println(" ---- */");
1376: out.printil("{");
1377: out.pushIndent();
1378:
1379: // Declare scripting variables with NESTED scope
1380: declareNestedScriptingVariables(n);
1381:
1382: /*
1383: * Save current values of scripting variables, so that the
1384: * scripting variables may be synchronized without affecting their
1385: * original values
1386: */
1387: saveScriptingVariables(n);
1388:
1389: out.printin(tagHandlerClass.getName());
1390: out.print(" ");
1391: out.print(tagHandlerVar);
1392: out.print(" = ");
1393: {
1394: out.print("new ");
1395: out.print(tagHandlerClass.getName());
1396: out.println("();");
1397: }
1398:
1399: generateSetters(n, tagHandlerVar, handlerInfo);
1400:
1401: if (implements TryCatchFinally) {
1402: out.printil("try {");
1403: out.pushIndent();
1404: }
1405: out.printin("int ");
1406: out.print(tagEvalVar);
1407: out.print(" = ");
1408: out.print(tagHandlerVar);
1409: out.println(".doStartTag();");
1410:
1411: // Synchronize AT_BEGIN and NESTED scripting variables
1412: if (!implements BodyTag) {
1413: syncScriptingVariables(n, VariableInfo.AT_BEGIN);
1414: syncScriptingVariables(n, VariableInfo.NESTED);
1415: }
1416:
1417: if (n.getBody() != null) {
1418: out.printin("if (");
1419: out.print(tagEvalVar);
1420: out
1421: .println(" != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {");
1422: out.pushIndent();
1423:
1424: if (implements BodyTag) {
1425: out.printin("if (");
1426: out.print(tagEvalVar);
1427: out
1428: .println(" != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {");
1429: // Assume EVAL_BODY_BUFFERED
1430: out.pushIndent();
1431: out
1432: .printil("javax.servlet.jsp.tagext.BodyContent _bc = pageContext.pushBody();");
1433: out.printil("_bc.clear();");
1434: out.printil("out = _bc;");
1435:
1436: out.printin(tagHandlerVar);
1437: out.println(".setBodyContent(_bc);");
1438: out.printin(tagHandlerVar);
1439: out.println(".doInitBody();");
1440:
1441: // Synchronize AT_BEGIN and NESTED scripting variables
1442: syncScriptingVariables(n, VariableInfo.AT_BEGIN);
1443: syncScriptingVariables(n, VariableInfo.NESTED);
1444:
1445: out.popIndent();
1446: out.printil("}");
1447: }
1448:
1449: if (implements IterationTag) {
1450: out.printil("do {");
1451: out.pushIndent();
1452: }
1453: }
1454: };
1455:
1456: private void generateCustomEnd(Node.CustomTag n,
1457: String tagHandlerVar, String tagEvalVar,
1458: boolean implements IterationTag,
1459: boolean implements BodyTag,
1460: boolean implements TryCatchFinally) {
1461:
1462: VariableInfo[] varInfos = n.getVariableInfos();
1463: TagVariableInfo[] tagVarInfos = n.getTagVariableInfos();
1464:
1465: if ((n.getBody() != null) && implements IterationTag) {
1466: out.printin("int evalDoAfterBody = ");
1467: out.print(tagHandlerVar);
1468: out.println(".doAfterBody();");
1469:
1470: // Synchronize AT_BEGIN and NESTED scripting variables
1471: if (implements BodyTag) {
1472: syncScriptingVariables(n, VariableInfo.AT_BEGIN);
1473: syncScriptingVariables(n, VariableInfo.NESTED);
1474: }
1475:
1476: out
1477: .printil("if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)");
1478: out.pushIndent();
1479: out.printil("break;");
1480: out.popIndent();
1481:
1482: out.popIndent();
1483: out.printil("} while (true);");
1484: }
1485:
1486: if (n.getBody() != null) {
1487: if (implements BodyTag) {
1488: out.printin("if (");
1489: out.print(tagEvalVar);
1490: out
1491: .println(" != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE)");
1492: out.pushIndent();
1493: out.printil("out = pageContext.popBody();");
1494: out.popIndent();
1495: }
1496:
1497: out.popIndent(); // EVAL_BODY
1498: out.printil("}");
1499: }
1500:
1501: out.printin("if (");
1502: out.print(tagHandlerVar);
1503: out
1504: .println(".doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE)");
1505: out.pushIndent();
1506: out.printil((methodNesting > 0) ? "return true;"
1507: : "return;");
1508: out.popIndent();
1509:
1510: // Synchronize AT_BEGIN and AT_END scripting variables
1511: syncScriptingVariables(n, VariableInfo.AT_BEGIN);
1512: syncScriptingVariables(n, VariableInfo.AT_END);
1513:
1514: // TryCatchFinally
1515: if (implements TryCatchFinally) {
1516: out.popIndent(); // try
1517: out.printil("} catch (Throwable _jspx_exception) {");
1518: out.pushIndent();
1519: out.printin(tagHandlerVar);
1520: out.println(".doCatch(_jspx_exception);");
1521: out.popIndent();
1522: out.printil("} finally {");
1523: out.pushIndent();
1524: out.printin(tagHandlerVar);
1525: out.println(".doFinally();");
1526: }
1527:
1528: /*if (ctxt.getOptions().isPoolingEnabled()) {
1529: out.printin(n.getTagHandlerPoolName());
1530: out.print(".reuse(");
1531: out.print(tagHandlerVar);
1532: out.println(");");
1533: }*/
1534:
1535: if (implements TryCatchFinally) {
1536: out.popIndent();
1537: out.println("}");
1538: }
1539:
1540: restoreScriptingVariables(n);
1541: out.popIndent();
1542: out.printil("}");
1543:
1544: n.setEndJavaLine(out.getJavaLine());
1545: }
1546:
1547: /*
1548: * Declares any NESTED scripting variables of the given custom tag.
1549: */
1550: private void declareNestedScriptingVariables(Node.CustomTag n) {
1551:
1552: TagVariableInfo[] tagVarInfos = n.getTagVariableInfos();
1553: VariableInfo[] nestedVarInfos = n.getNestedVariableInfos();
1554: if ((nestedVarInfos == null) && (tagVarInfos == null)) {
1555: return;
1556: }
1557:
1558: if (nestedVarInfos != null) {
1559: for (int i = 0; i < nestedVarInfos.length; i++) {
1560: String name = nestedVarInfos[i].getVarName();
1561: out.printin(nestedVarInfos[i].getClassName());
1562: out.print(" ");
1563: out.print(name);
1564: out.println(" = null;");
1565: }
1566: } else {
1567: for (int i = 0; i < tagVarInfos.length; i++) {
1568: if ((tagVarInfos[i].getScope() == VariableInfo.NESTED)
1569: && tagVarInfos[i].getDeclare()) {
1570: String name = tagVarInfos[i].getNameGiven();
1571: if (name == null) {
1572: name = n.getTagData().getAttributeString(
1573: tagVarInfos[i]
1574: .getNameFromAttribute());
1575: }
1576: out.printin(tagVarInfos[i].getClassName());
1577: out.print(" ");
1578: out.print(name);
1579: out.println(" = null;");
1580: }
1581: }
1582: }
1583: }
1584:
1585: /*
1586: * This method is called as part of the custom tag's start element.
1587: *
1588: * If the given custom tag has a custom nesting level greater than 0,
1589: * save the current values of its scripting variables to
1590: * temporary variables, so those values may be restored in the tag's
1591: * end element. This way, the scripting variables may be synchronized
1592: * by the given tag without affecting their original values.
1593: */
1594: private void saveScriptingVariables(Node.CustomTag n) {
1595: if (n.getCustomNestingLevel() == 0) {
1596: return;
1597: }
1598:
1599: TagVariableInfo[] tagVarInfos = n.getTagVariableInfos();
1600: VariableInfo[] varInfos = n.getVariableInfos();
1601: if ((varInfos == null) && (tagVarInfos == null)) {
1602: return;
1603: }
1604:
1605: if (varInfos != null) {
1606: for (int i = 0; i < varInfos.length; i++) {
1607: String varName = varInfos[i].getVarName();
1608: String tmpVarName = "_jspx_" + varName + "_"
1609: + n.getCustomNestingLevel();
1610: out.printin(varInfos[i].getClassName());
1611: out.print(" ");
1612: out.print(tmpVarName);
1613: out.print(" = ");
1614: out.print(varName);
1615: out.println(";");
1616: }
1617: } else {
1618: for (int i = 0; i < tagVarInfos.length; i++) {
1619: String varName = tagVarInfos[i].getNameGiven();
1620: if (varName == null) {
1621: varName = n.getTagData().getAttributeString(
1622: tagVarInfos[i].getNameFromAttribute());
1623: }
1624: String tmpVarName = "_jspx_" + varName + "_"
1625: + n.getCustomNestingLevel();
1626: out.printin(tagVarInfos[i].getClassName());
1627: out.print(" ");
1628: out.print(tmpVarName);
1629: out.print(" = ");
1630: out.print(varName);
1631: out.println(";");
1632: }
1633: }
1634: }
1635:
1636: /*
1637: * This method is called as part of the custom tag's end element.
1638: *
1639: * If the given custom tag has a custom nesting level greater than 0,
1640: * restore its scripting variables to their original values that were
1641: * saved in the tag's start element.
1642: */
1643: private void restoreScriptingVariables(Node.CustomTag n) {
1644: if (n.getCustomNestingLevel() == 0) {
1645: return;
1646: }
1647:
1648: TagVariableInfo[] tagVarInfos = n.getTagVariableInfos();
1649: VariableInfo[] varInfos = n.getVariableInfos();
1650: if ((varInfos == null) && (tagVarInfos == null)) {
1651: return;
1652: }
1653:
1654: if (varInfos != null) {
1655: for (int i = 0; i < varInfos.length; i++) {
1656: String varName = varInfos[i].getVarName();
1657: String tmpVarName = "_jspx_" + varName + "_"
1658: + n.getCustomNestingLevel();
1659: out.printin(varName);
1660: out.print(" = ");
1661: out.print(tmpVarName);
1662: out.println(";");
1663: }
1664: } else {
1665: for (int i = 0; i < tagVarInfos.length; i++) {
1666: String varName = tagVarInfos[i].getNameGiven();
1667: if (varName == null) {
1668: varName = n.getTagData().getAttributeString(
1669: tagVarInfos[i].getNameFromAttribute());
1670: }
1671: String tmpVarName = "_jspx_" + varName + "_"
1672: + n.getCustomNestingLevel();
1673: out.printin(varName);
1674: out.print(" = ");
1675: out.print(tmpVarName);
1676: out.println(";");
1677: }
1678: }
1679: }
1680:
1681: /*
1682: * Synchronizes the scripting variables of the given custom tag for
1683: * the given scope.
1684: */
1685: private void syncScriptingVariables(Node.CustomTag n, int scope) {
1686: TagVariableInfo[] tagVarInfos = n.getTagVariableInfos();
1687: VariableInfo[] varInfos = n.getVariableInfos();
1688:
1689: if ((varInfos == null) && (tagVarInfos == null)) {
1690: return;
1691: }
1692:
1693: if (varInfos != null) {
1694: for (int i = 0; i < varInfos.length; i++) {
1695: if (varInfos[i].getScope() == scope) {
1696: out.printin(varInfos[i].getVarName());
1697: out.print(" = (");
1698: out.print(varInfos[i].getClassName());
1699: out.print(") pageContext.findAttribute(");
1700: out.print(quote(varInfos[i].getVarName()));
1701: out.println(");");
1702: }
1703: }
1704: } else {
1705: for (int i = 0; i < tagVarInfos.length; i++) {
1706: if (tagVarInfos[i].getScope() == scope) {
1707: String name = tagVarInfos[i].getNameGiven();
1708: if (name == null) {
1709: name = n.getTagData().getAttributeString(
1710: tagVarInfos[i]
1711: .getNameFromAttribute());
1712: }
1713: out.printin(name);
1714: out.print(" = (");
1715: out.print(tagVarInfos[i].getClassName());
1716: out.print(") pageContext.findAttribute(");
1717: out.print(quote(name));
1718: out.println(");");
1719: }
1720: }
1721: }
1722: }
1723:
1724: /*
1725: * Creates a tag variable name by concatenating the given prefix and
1726: * shortName and replacing '-' with "$1", '.' with "$2", and ':' with
1727: * "$3".
1728: */
1729: private String createTagVarName(String fullName, String prefix,
1730: String shortName) {
1731: if (prefix.indexOf('-') >= 0)
1732: prefix = JspUtil.replace(prefix, '-', "$1");
1733: if (prefix.indexOf('.') >= 0)
1734: prefix = JspUtil.replace(prefix, '.', "$2");
1735:
1736: if (shortName.indexOf('-') >= 0)
1737: shortName = JspUtil.replace(shortName, '-', "$1");
1738: if (shortName.indexOf('.') >= 0)
1739: shortName = JspUtil.replace(shortName, '.', "$2");
1740: if (shortName.indexOf(':') >= 0)
1741: shortName = JspUtil.replace(shortName, ':', "$3");
1742:
1743: synchronized (tagVarNumbers) {
1744: String varName = prefix + "_" + shortName + "_";
1745: if (tagVarNumbers.get(fullName) != null) {
1746: Integer i = (Integer) tagVarNumbers.get(fullName);
1747: varName = varName + i.intValue();
1748: tagVarNumbers.put(fullName, new Integer(i
1749: .intValue() + 1));
1750: return varName;
1751: } else {
1752: tagVarNumbers.put(fullName, new Integer(1));
1753: return varName + "0";
1754: }
1755: }
1756: }
1757:
1758: private void generateSetters(Node.CustomTag n,
1759: String tagHandlerVar, TagHandlerInfo handlerInfo)
1760: throws JasperException {
1761:
1762: out.printin(tagHandlerVar);
1763: out.println(".setPageContext(pageContext);");
1764: out.printin(tagHandlerVar);
1765: out.print(".setParent(");
1766: out.print(parent);
1767: out.println(");");
1768:
1769: Node.JspAttribute[] attrs = n.getJspAttributes();
1770: for (int i = 0; i < attrs.length; i++) {
1771: String attrValue = attrs[i].getValue();
1772: if (attrValue == null) {
1773: continue;
1774: }
1775: String attrName = attrs[i].getName();
1776: Method m = handlerInfo.getSetterMethod(attrName);
1777: /*if (m == null) {
1778: err.jspError(n, "jsp.error.unable.to_find_method",
1779: attrName);
1780: }*/
1781:
1782: Class c[] = m.getParameterTypes();
1783: // XXX assert(c.length > 0)
1784:
1785: if (!attrs[i].isExpression()) {
1786: attrValue = convertString(c[0], attrValue,
1787: attrName, handlerInfo
1788: .getPropertyEditorClass(attrName));
1789: }
1790:
1791: out.printin(tagHandlerVar);
1792: out.print(".");
1793: out.print(m.getName());
1794: out.print("(");
1795: out.print(attrValue);
1796: out.println(");");
1797: }
1798: }
1799:
1800: private String convertString(Class c, String s,
1801: String attrName, Class propEditorClass)
1802: throws JasperException {
1803:
1804: if (propEditorClass != null) {
1805: return "("
1806: + c.getName()
1807: + ")JspRuntimeLibrary.getValueFromBeanInfoPropertyEditor("
1808: + c.getName() + ".class, \"" + attrName
1809: + "\", " + quote(s) + ", "
1810: + propEditorClass.getName() + ".class)";
1811: } else if (c == String.class) {
1812: return quote(s);
1813: } else if (c == boolean.class) {
1814: return Boolean.valueOf(s).toString();
1815: } else if (c == Boolean.class) {
1816: return "new Boolean(" + Boolean.valueOf(s).toString()
1817: + ")";
1818: } else if (c == byte.class) {
1819: return "((byte)" + Byte.valueOf(s).toString() + ")";
1820: } else if (c == Byte.class) {
1821: return "new Byte((byte)" + Byte.valueOf(s).toString()
1822: + ")";
1823: } else if (c == char.class) {
1824: // non-normative (normative method would fail to compile)
1825: if (s.length() > 0) {
1826: char ch = s.charAt(0);
1827: // this trick avoids escaping issues
1828: return "((char) " + (int) ch + ")";
1829: } else {
1830: throw new NumberFormatException(
1831: "jsp.error.bad_string_char");
1832: }
1833: } else if (c == Character.class) {
1834: // non-normative (normative method would fail to compile)
1835: if (s.length() > 0) {
1836: char ch = s.charAt(0);
1837: // this trick avoids escaping issues
1838: return "new Character((char) " + (int) ch + ")";
1839: } else {
1840: throw new NumberFormatException(
1841: "jsp.error.bad_string_Character");
1842: }
1843: } else if (c == double.class) {
1844: return Double.valueOf(s).toString();
1845: } else if (c == Double.class) {
1846: return "new Double(" + Double.valueOf(s).toString()
1847: + ")";
1848: } else if (c == float.class) {
1849: return Float.valueOf(s).toString() + "f";
1850: } else if (c == Float.class) {
1851: return "new Float(" + Float.valueOf(s).toString()
1852: + "f)";
1853: } else if (c == int.class) {
1854: return Integer.valueOf(s).toString();
1855: } else if (c == Integer.class) {
1856: return "new Integer(" + Integer.valueOf(s).toString()
1857: + ")";
1858: } else if (c == short.class) {
1859: return "((short) " + Short.valueOf(s).toString() + ")";
1860: } else if (c == Short.class) {
1861: return "new Short(" + Short.valueOf(s).toString() + ")";
1862: } else if (c == long.class) {
1863: return Long.valueOf(s).toString() + "l";
1864: } else if (c == Long.class) {
1865: return "new Long(" + Long.valueOf(s).toString() + "l)";
1866: } else if (c == Object.class) {
1867: return "new String(" + quote(s) + ")";
1868: } else {
1869: return "("
1870: + c.getName()
1871: + ")JspRuntimeLibrary.getValueFromPropertyEditorManager("
1872: + c.getName() + ".class, \"" + attrName
1873: + "\", " + quote(s) + ")";
1874: }
1875: }
1876: }
1877:
1878: /**
1879: * Generates the ending part of the static portion of the servelet.
1880: */
1881: private void generatePostamble(Node.Nodes page) {
1882: out.popIndent();
1883: out.printil("} catch (Throwable t) {");
1884: out.pushIndent();
1885:
1886: out.printil("out = _jspx_out;");
1887: out.printil("if (out != null && out.getBufferSize() != 0)");
1888: out.pushIndent();
1889: out.printil("out.clearBuffer();");
1890: out.popIndent();
1891:
1892: out
1893: .printil("if (pageContext != null) pageContext.handlePageException(t);");
1894:
1895: out.popIndent();
1896: out.printil("} finally {");
1897: out.pushIndent();
1898:
1899: out
1900: .printil("if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext);");
1901:
1902: out.popIndent();
1903: out.printil("}");
1904:
1905: // Close the service method
1906: out.popIndent();
1907: out.printil("}");
1908:
1909: // Append any methods that were generated
1910: out.print(methodsBuffer.toString());
1911:
1912: // generate class definition for JspxState
1913: if (maxTagNesting > 0) {
1914: generateJspState();
1915: }
1916:
1917: // Close the class definition
1918: out.popIndent();
1919: out.printil("}");
1920: }
1921:
1922: /**
1923: * Constructor.
1924: */
1925: Generator(ServletWriter out, JspC compiler) {
1926: this .compiler = compiler;
1927: this .out = out;
1928: methodsBuffer = new MethodsBuffer();
1929: //err = compiler.getErrorDispatcher();
1930: ctxt = compiler.getWebContext();
1931: pageInfo = compiler.getPageInfo();
1932: beanInfo = pageInfo.getBeanRepository();
1933: //breakAtLF = ctxt.getOptions().getMappedFile();
1934: //if (ctxt.getOptions().isPoolingEnabled()) {
1935: // tagHandlerPoolNames = new Vector();
1936: //}
1937: }
1938:
1939: /**
1940: * The main entry for Generator.
1941: * @param out The servlet output writer
1942: * @param compiler The compiler
1943: * @param page The input page
1944: */
1945: public static void generate(ServletWriter out, JspC compiler,
1946: Node.Nodes page) throws JasperException, JspToJavaException {
1947: Generator gen = new Generator(out, compiler);
1948:
1949: //if (gen.ctxt.getOptions().isPoolingEnabled())
1950: //{
1951: // gen.compileTagHandlerPoolList(page);
1952: //}
1953: gen.generatePreamble(page);
1954: page.visit(gen.new GenerateVisitor(out, gen.methodsBuffer));
1955: gen.generatePostamble(page);
1956: }
1957:
1958: /**
1959: * Class storing the result of introspecting a custom tag handler.
1960: */
1961: private static class TagHandlerInfo {
1962:
1963: private Hashtable methodMaps;
1964: private Hashtable propertyEditorMaps;
1965: private Class tagHandlerClass;
1966:
1967: /**
1968: * Constructor.
1969: *
1970: * @param n The custom tag whose tag handler is to be loaded and
1971: * introspected
1972: * @param tagClassName Name of tag handler class to load
1973: * @param loader Class loader to use
1974: * @param err Error dispatcher
1975: */
1976: TagHandlerInfo(Node n, String tagClassName)
1977: throws JasperException {
1978:
1979: // Load the tag handler class with the given name
1980: tagHandlerClass = null;
1981: try {
1982: tagHandlerClass = this .getClass().getClassLoader()
1983: .loadClass(tagClassName);
1984:
1985: } catch (Exception e) {
1986: System.out.println("jsp.error.unable.loadclass ->"
1987: + tagClassName);
1988: //err.jspError(n, "jsp.error.unable.loadclass", tagClassName, e);
1989: }
1990:
1991: this .methodMaps = new Hashtable();
1992: this .propertyEditorMaps = new Hashtable();
1993:
1994: try {
1995: BeanInfo tagClassInfo = Introspector
1996: .getBeanInfo(tagHandlerClass);
1997: PropertyDescriptor[] pd = tagClassInfo
1998: .getPropertyDescriptors();
1999: for (int i = 0; i < pd.length; i++) {
2000: /*
2001: * FIXME: should probably be checking for things like
2002: * pageContext, bodyContent, and parent here -akv
2003: */
2004: if (pd[i].getWriteMethod() != null) {
2005: methodMaps.put(pd[i].getName(), pd[i]
2006: .getWriteMethod());
2007: }
2008: if (pd[i].getPropertyEditorClass() != null)
2009: propertyEditorMaps.put(pd[i].getName(), pd[i]
2010: .getPropertyEditorClass());
2011: }
2012: } catch (IntrospectionException ie) {
2013: //err.jspError(n, "jsp.error.introspect.taghandler",tagClassName, ie);
2014: }
2015: }
2016:
2017: /**
2018: * XXX
2019: */
2020: public Method getSetterMethod(String attrName) {
2021: return (Method) methodMaps.get(attrName);
2022: }
2023:
2024: /**
2025: * XXX
2026: */
2027: public Class getPropertyEditorClass(String attrName) {
2028: return (Class) propertyEditorMaps.get(attrName);
2029: }
2030:
2031: /**
2032: * XXX
2033: */
2034: public Class getTagHandlerClass() {
2035: return tagHandlerClass;
2036: }
2037: }
2038:
2039: private static class MethodsBuffer {
2040:
2041: private java.io.CharArrayWriter charWriter;
2042: private ServletWriter out;
2043:
2044: MethodsBuffer() {
2045: charWriter = new java.io.CharArrayWriter();
2046: out = new ServletWriter(new java.io.PrintWriter(charWriter));
2047: }
2048:
2049: public ServletWriter getOut() {
2050: return out;
2051: }
2052:
2053: public String toString() {
2054: return charWriter.toString();
2055: }
2056: }
2057: }
|