org.apache.jasper.compiler.Generator Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jasper.compiler;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.HashSet;
import javax.el.ValueExpression;
import javax.el.MethodExpression;
import javax.servlet.jsp.tagext.TagAttributeInfo;
import javax.servlet.jsp.tagext.TagInfo;
import javax.servlet.jsp.tagext.TagVariableInfo;
import javax.servlet.jsp.tagext.VariableInfo;
import javax.servlet.jsp.tagext.JspIdConsumer;
import org.apache.jasper.Constants;
import org.apache.jasper.JasperException;
import org.apache.jasper.JspCompilationContext;
import org.apache.jasper.runtime.JspRuntimeLibrary;
import org.xml.sax.Attributes;
/**
* Generate Java source from Nodes
*
* @author Anil K. Vijendran
* @author Danno Ferrin
* @author Mandar Raje
* @author Rajiv Mordani
* @author Pierre Delisle
*
* Tomcat 4.1.x and Tomcat 5:
* @author Kin-man Chung
* @author Jan Luehe
* @author Shawn Bayern
* @author Mark Roth
* @author Denis Benoit
*/
class Generator {
private static final Class[] OBJECT_CLASS = { Object.class };
private ServletWriter out;
private ArrayList methodsBuffered;
private FragmentHelperClass fragmentHelperClass;
private ErrorDispatcher err;
private BeanRepository beanInfo;
private JspCompilationContext ctxt;
private boolean isPoolingEnabled;
private boolean breakAtLF;
private boolean genBytes;
private PageInfo pageInfo;
private Set tagHandlerPoolNames;
private GenBuffer arrayBuffer;
/**
* @param s the input string
* @return quoted and escaped string, per Java rule
*/
static String quote(String s) {
if (s == null)
return "null";
return '"' + escape(s) + '"';
}
/**
* @param s the input string
* @return escaped string, per Java rule
*/
static String escape(String s) {
if (s == null)
return "";
StringBuilder b = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '"')
b.append('\\').append('"');
else if (c == '\\')
b.append('\\').append('\\');
else if (c == '\n')
b.append('\\').append('n');
else if (c == '\r')
b.append('\\').append('r');
else
b.append(c);
}
return b.toString();
}
/**
* Single quote and escape a character
*/
static String quote(char c) {
StringBuilder b = new StringBuilder();
b.append('\'');
if (c == '\'')
b.append('\\').append('\'');
else if (c == '\\')
b.append('\\').append('\\');
else if (c == '\n')
b.append('\\').append('n');
else if (c == '\r')
b.append('\\').append('r');
else
b.append(c);
b.append('\'');
return b.toString();
}
/**
* Generates declarations. This includes "info" of the page directive,
* and scriptlet declarations.
*/
private void generateDeclarations(Node.Nodes page) throws JasperException {
class DeclarationVisitor extends Node.Visitor {
private boolean getServletInfoGenerated = false;
/*
* Generates getServletInfo() method that returns the value of the
* page directive's 'info' attribute, if present.
*
* The Validator has already ensured that if the translation unit
* contains more than one page directive with an 'info' attribute,
* their values match.
*/
public void visit(Node.PageDirective n) throws JasperException {
if (getServletInfoGenerated) {
return;
}
String info = n.getAttributeValue("info");
if (info == null)
return;
getServletInfoGenerated = true;
out.printil("public String getServletInfo() {");
out.pushIndent();
out.printin("return ");
out.print(quote(info));
out.println(";");
out.popIndent();
out.printil("}");
out.println();
}
public void visit(Node.Declaration n) throws JasperException {
n.setBeginJavaLine(out.getJavaLine());
out.printMultiLn(n.getText());
out.println();
n.setEndJavaLine(out.getJavaLine());
}
// Custom Tags may contain declarations from tag plugins.
public void visit(Node.CustomTag n) throws JasperException {
if (n.useTagPlugin()) {
if (n.getAtSTag() != null) {
n.getAtSTag().visit(this);
}
visitBody(n);
if (n.getAtETag() != null) {
n.getAtETag().visit(this);
}
} else {
visitBody(n);
}
}
}
out.println();
page.visit(new DeclarationVisitor());
}
/**
* Compiles list of tag handler pool names.
*/
private void compileTagHandlerPoolList(Node.Nodes page)
throws JasperException {
class TagHandlerPoolVisitor extends Node.Visitor {
private Set names = new HashSet();
/*
* Constructor
*
* @param v Set of tag handler pool names to populate
*/
TagHandlerPoolVisitor(Set v) {
names = v;
}
/*
* Gets the name of the tag handler pool for the given custom tag
* and adds it to the list of tag handler pool names unless it is
* already contained in it.
*/
public void visit(Node.CustomTag n) throws JasperException {
if (!n.implementsSimpleTag()) {
String name =
createTagHandlerPoolName(
n.getPrefix(),
n.getLocalName(),
n.getAttributes(),
n.hasEmptyBody());
n.setTagHandlerPoolName(name);
if (!names.contains(name)) {
names.add(name);
}
}
visitBody(n);
}
/*
* Creates the name of the tag handler pool whose tag handlers may
* be (re)used to service this action.
*
* @return The name of the tag handler pool
*/
private String createTagHandlerPoolName(
String prefix,
String shortName,
Attributes attrs,
boolean hasEmptyBody) {
String poolName = null;
poolName = "_jspx_tagPool_" + prefix + "_" + shortName;
if (attrs != null) {
String[] attrNames = new String[attrs.getLength()];
for (int i = 0; i < attrNames.length; i++) {
attrNames[i] = attrs.getQName(i);
}
Arrays.sort(attrNames, Collections.reverseOrder());
for (int i = 0; i < attrNames.length; i++) {
poolName = poolName + "_" + attrNames[i];
}
}
if (hasEmptyBody) {
poolName = poolName + "_nobody";
}
return JspUtil.makeXmlJavaIdentifier(poolName);
}
}
page.visit(new TagHandlerPoolVisitor(tagHandlerPoolNames));
}
/**
* Generates the _jspInit() method for instantiating the tag handler pools.
* For tag file, _jspInit has to be invoked manually, and the ServletConfig
* object explicitly passed.
*/
private void generateTagHandlerInit() {
if (!isPoolingEnabled || tagHandlerPoolNames.isEmpty()) {
return;
}
if (ctxt.isTagFile()) {
out.printil("private void _jspInit(ServletConfig config) {");
} else {
out.printil("public void _jspInit() {");
}
out.pushIndent();
for (String tagHandlerPoolName: tagHandlerPoolNames) {
out.printin(tagHandlerPoolName);
out.print(
" = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(");
if (ctxt.isTagFile()) {
out.print("config");
} else {
out.print("getServletConfig()");
}
out.println(");");
}
out.popIndent();
out.printil("}");
out.println();
}
/**
* Generates the _jspDestroy() method which is responsible for calling the
* release() method on every tag handler in any of the tag handler pools.
*/
private void generateTagHandlerDestroy() {
if (!isPoolingEnabled || tagHandlerPoolNames.isEmpty()) {
return;
}
out.printil("public void _jspDestroy() {");
out.pushIndent();
for (String tagHandlerPoolName: tagHandlerPoolNames) {
out.printin(tagHandlerPoolName);
out.println(".release();");
}
out.popIndent();
out.printil("}");
out.println();
}
/**
* Generate preamble package name
* (shared by servlet and tag handler preamble generation)
*/
private void genPreamblePackage(String packageName)
throws JasperException {
if (!"".equals(packageName) && packageName != null) {
out.printil("package " + packageName + ";");
out.println();
}
}
/**
* Generate preamble imports
* (shared by servlet and tag handler preamble generation)
*/
private void genPreambleImports() throws JasperException {
Iterator iter = pageInfo.getImports().iterator();
while (iter.hasNext()) {
out.printin("import ");
out.print(iter.next());
out.println(";");
}
out.println();
}
/**
* Generation of static initializers in preamble.
* For example, dependant list, el function map, prefix map.
* (shared by servlet and tag handler preamble generation)
*/
private void genPreambleStaticInitializers() throws JasperException {
out.printil("private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();");
out.println();
// Static data for getDependants()
out.printil("private static java.util.List _jspx_dependants;");
out.println();
List dependants = pageInfo.getDependants();
Iterator iter = dependants.iterator();
if (!dependants.isEmpty()) {
out.printil("static {");
out.pushIndent();
out.printin("_jspx_dependants = new java.util.ArrayList(");
out.print("" + dependants.size());
out.println(");");
while (iter.hasNext()) {
out.printin("_jspx_dependants.add(\"");
out.print(iter.next());
out.println("\");");
}
out.popIndent();
out.printil("}");
out.println();
}
// Codes to support genStringAsByteArray option
// Generate a static variable for the initial response encoding
if (genBytes) {
// first get the respons encoding
String contentType = pageInfo.getContentType();
String encoding = "ISO-8859-1";
int i = contentType.indexOf("charset=");
if (i > 0)
encoding = contentType.substring(i+8);
// Make sure the encoding is supported
// Assume that this can be determined at compile time
try {
"testing".getBytes(encoding);
out.printin("private static final String _jspx_encoding = ");
out.print(quote(encoding));
out.println(";");
out.printil("private boolean _jspx_gen_bytes = true;");
out.printil("private boolean _jspx_encoding_tested;");
} catch (java.io.UnsupportedEncodingException ex) {
genBytes = false;
}
}
}
/**
* Declare tag handler pools (tags of the same type and with the same
* attribute set share the same tag handler pool)
* (shared by servlet and tag handler preamble generation)
*/
private void genPreambleClassVariableDeclarations(String className)
throws JasperException {
if (isPoolingEnabled) {
if (!tagHandlerPoolNames.isEmpty()) {
for (String tagHandlerPoolName: tagHandlerPoolNames) {
out.printil(
"private org.apache.jasper.runtime.TagHandlerPool "
+ tagHandlerPoolName + ";");
}
out.println();
}
}
out.printil("private org.glassfish.jsp.api.ResourceInjector "
+ "_jspx_resourceInjector;");
out.println();
}
/**
* Declare general-purpose methods
* (shared by servlet and tag handler preamble generation)
*/
private void genPreambleMethods() throws JasperException {
// Method used to get compile time file dependencies
out.printil("public java.util.List getDependants() {");
out.pushIndent();
out.printil("return _jspx_dependants;");
out.popIndent();
out.printil("}");
out.println();
// Method to get bytes from String
if (genBytes) {
out.printil("private static byte[] _jspx_getBytes(String s) {");
out.pushIndent();
out.printil("try {");
out.pushIndent();
out.printil("return s.getBytes(_jspx_encoding);");
out.popIndent();
out.printil("} catch (java.io.UnsupportedEncodingException ex) {");
out.printil("}");
out.printil("return null;");
out.popIndent();
out.printil("}");
out.println();
// Generate code to see if the response encoding has been set
// differently from the encoding declared in the page directive.
// Note that we only need to do the test once. The assumption
// is that the encoding cannot be changed once some data has been
// written.
out.printil("private boolean _jspx_same_encoding(String encoding) {");
out.pushIndent();
out.printil("if (! _jspx_encoding_tested) {");
out.pushIndent();
out.printil("_jspx_gen_bytes = _jspx_encoding.equals(encoding);");
out.printil("_jspx_encoding_tested = true;");
out.popIndent();
out.printil("}");
out.printil("return _jspx_gen_bytes;");
out.popIndent();
out.printil("}");
out.println();
}
generateTagHandlerInit();
generateTagHandlerDestroy();
}
/**
* Generates the beginning of the static portion of the servlet.
*/
private void generatePreamble(Node.Nodes page) throws JasperException {
String servletPackageName = ctxt.getServletPackageName();
String servletClassName = ctxt.getServletClassName();
String serviceMethodName = Constants.SERVICE_METHOD_NAME;
// First the package name:
genPreamblePackage(servletPackageName);
// Generate imports
genPreambleImports();
// Generate class declaration
out.printin("public final class ");
out.print(servletClassName);
out.print(" extends ");
out.println(pageInfo.getExtends());
out.printin(
" implements org.apache.jasper.runtime.JspSourceDependent");
if (!pageInfo.isThreadSafe()) {
out.println(",");
out.printin(" SingleThreadModel");
}
out.println(" {");
out.pushIndent();
// Class body begins here
generateDeclarations(page);
// Static initializations here
genPreambleStaticInitializers();
// Class variable declarations
genPreambleClassVariableDeclarations(servletClassName);
// Constructor
// generateConstructor(className);
// Methods here
genPreambleMethods();
// Now the service method
out.printin("public void ");
out.print(serviceMethodName);
out.println(
"(HttpServletRequest request, HttpServletResponse response)");
out.println(" throws java.io.IOException, ServletException {");
out.pushIndent();
out.println();
// Local variable declarations
out.printil("PageContext pageContext = null;");
if (pageInfo.isSession())
out.printil("HttpSession session = null;");
if (pageInfo.isErrorPage()) {
out.printil(
"Throwable exception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request);");
out.printil("if (exception != null) {");
out.pushIndent();
out.printil(
"response.setStatus((Integer)request.getAttribute(\"javax.servlet.error.status_code\"));");
out.popIndent();
out.printil("}");
}
out.printil("ServletContext application = null;");
out.printil("ServletConfig config = null;");
out.printil("JspWriter out = null;");
out.printil("Object page = this;");
out.printil("JspWriter _jspx_out = null;");
out.printil("PageContext _jspx_page_context = null;");
out.println();
out.printil("try {");
out.pushIndent();
out.printin("response.setContentType(");
out.print(quote(pageInfo.getContentType()));
out.println(");");
if (ctxt.getOptions().isXpoweredBy()) {
out.printil("response.setHeader(\"X-Powered-By\", \"" +
Constants.JSP_NAME + "\");");
}
out.printil(
"pageContext = _jspxFactory.getPageContext(this, request, response,");
out.printin("\t\t\t");
out.print(quote(pageInfo.getErrorPage()));
out.print(", " + pageInfo.isSession());
out.print(", " + pageInfo.getBuffer());
out.print(", " + pageInfo.isAutoFlush());
out.println(");");
out.printil("_jspx_page_context = pageContext;");
out.printil("application = pageContext.getServletContext();");
out.printil("config = pageContext.getServletConfig();");
if (pageInfo.isSession())
out.printil("session = pageContext.getSession();");
out.printil("out = pageContext.getOut();");
out.printil("_jspx_out = out;");
out.printil("_jspx_resourceInjector = (org.glassfish.jsp.api.ResourceInjector) application.getAttribute(\"com.sun.appserv.jsp.resource.injector\");");
out.println();
}
/**
* Generates an XML Prolog, which includes an XML declaration and
* an XML doctype declaration.
*/
private void generateXmlProlog(Node.Nodes page) {
/*
* An XML declaration is generated under the following conditions:
*
* - 'omit-xml-declaration' attribute of action is set to
* "no" or "false"
* - JSP document without a
*/
String omitXmlDecl = pageInfo.getOmitXmlDecl();
if ((omitXmlDecl != null && !JspUtil.booleanValue(omitXmlDecl))
|| (omitXmlDecl == null
&& page.getRoot().isXmlSyntax()
&& !pageInfo.hasJspRoot()
&& !ctxt.isTagFile())) {
String cType = pageInfo.getContentType();
String charSet = cType.substring(cType.indexOf("charset=") + 8);
out.printil(
"out.write(\"\\n\");");
}
/*
* Output a DOCTYPE declaration if the doctype-root-element appears.
* If doctype-public appears:
*
* else
*
*/
String doctypeName = pageInfo.getDoctypeName();
if (doctypeName != null) {
String doctypePublic = pageInfo.getDoctypePublic();
String doctypeSystem = pageInfo.getDoctypeSystem();
out.printin("out.write(\"\\n\");");
}
}
/*
* Generates the constructor.
* (shared by servlet and tag handler preamble generation)
*/
private void generateConstructor(String className) {
out.printil("public " + className + "() {");
out.printil("}");
out.println();
}
/**
* A visitor that generates codes for the elements in the page.
*/
class GenerateVisitor extends Node.Visitor {
/*
* HashMap containing introspection information on tag handlers:
* : tag prefix
* : hashtable containing introspection on tag handlers:
* : tag short name
* : introspection info of tag handler for
* tag
*/
private HashMap> handlerInfos;
private HashMap tagVarNumbers;
private String parent;
private boolean isSimpleTagParent; // Is parent a SimpleTag?
private String pushBodyCountVar;
private String simpleTagHandlerVar;
private boolean isSimpleTagHandler;
private boolean isFragment;
private boolean isTagFile;
private ServletWriter out;
private ArrayList methodsBuffered;
private FragmentHelperClass fragmentHelperClass;
private int methodNesting;
private int arrayCount;
private HashMap textMap;
/**
* Constructor.
*/
public GenerateVisitor(
boolean isTagFile,
ServletWriter out,
ArrayList methodsBuffered,
FragmentHelperClass fragmentHelperClass) {
this.isTagFile = isTagFile;
this.out = out;
this.methodsBuffered = methodsBuffered;
this.fragmentHelperClass = fragmentHelperClass;
methodNesting = 0;
handlerInfos = new HashMap>();
tagVarNumbers = new HashMap();
textMap = new HashMap();
}
/**
* Returns an attribute value, optionally URL encoded. If
* the value is a runtime expression, the result is the expression
* itself, as a string. If the result is an EL expression, we insert
* a call to the interpreter. If the result is a Named Attribute
* we insert the generated variable name. Otherwise the result is a
* string literal, quoted and escaped.
*
* @param attr An JspAttribute object
* @param encode true if to be URL encoded
* @param expectedType the expected type for an EL evaluation
* (ignored for attributes that aren't EL expressions)
*/
private String attributeValue(
Node.JspAttribute attr,
boolean encode,
Class expectedType) {
String v = attr.getValue();
if (!attr.isNamedAttribute() && (v == null))
return "";
if (attr.isExpression()) {
if (encode) {
return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode(String.valueOf("
+ v
+ "), request.getCharacterEncoding())";
}
return v;
} else if (attr.isELInterpreterInput()) {
v = JspUtil.interpreterCall(
this.isTagFile,
v,
expectedType,
attr.getEL().getMapName(),
null, null, null);
if (encode) {
return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("
+ v
+ ", request.getCharacterEncoding())";
}
return v;
} else if (attr.isNamedAttribute()) {
return attr.getNamedAttributeNode().getTemporaryVariableName();
} else {
if (encode) {
return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("
+ quote(v)
+ ", request.getCharacterEncoding())";
}
return quote(v);
}
}
/**
* Prints the attribute value specified in the param action, in the
* form of name=value string.
*
* @param n the parent node for the param action nodes.
*/
private void printParams(Node n, String pageParam, boolean literal)
throws JasperException {
class ParamVisitor extends Node.Visitor {
String separator;
ParamVisitor(String separator) {
this.separator = separator;
}
public void visit(Node.ParamAction n) throws JasperException {
out.print(" + ");
out.print(separator);
out.print(" + ");
out.print(
"org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("
+ quote(n.getTextAttribute("name"))
+ ", request.getCharacterEncoding())");
out.print("+ \"=\" + ");
out.print(attributeValue(n.getValue(), true, String.class));
// The separator is '&' after the second use
separator = "\"&\"";
}
}
String sep;
if (literal) {
sep = pageParam.indexOf('?') > 0 ? "\"&\"" : "\"?\"";
} else {
sep = "((" + pageParam + ").indexOf('?')>0? '&': '?')";
}
if (n.getBody() != null) {
n.getBody().visit(new ParamVisitor(sep));
}
}
public void visit(Node.Expression n) throws JasperException {
n.setBeginJavaLine(out.getJavaLine());
out.printil("out.print(" + n.getText() + ");");
n.setEndJavaLine(out.getJavaLine());
}
public void visit(Node.Scriptlet n) throws JasperException {
n.setBeginJavaLine(out.getJavaLine());
out.printMultiLn(n.getText());
out.println();
n.setEndJavaLine(out.getJavaLine());
}
public void visit(Node.ELExpression n) throws JasperException {
n.setBeginJavaLine(out.getJavaLine());
if (n.getEL() != null) {
out.printil(
"out.write("
+ JspUtil.interpreterCall(
this.isTagFile,
n.getText(),
String.class,
n.getEL().getMapName(),
null, null, null)
+ ");");
} else {
out.printil(
"out.write("
+ quote(n.getText())
+ ");");
}
n.setEndJavaLine(out.getJavaLine());
}
public void visit(Node.IncludeAction n) throws JasperException {
String flush = n.getTextAttribute("flush");
Node.JspAttribute page = n.getPage();
boolean isFlush = false; // default to false;
if ("true".equals(flush))
isFlush = true;
n.setBeginJavaLine(out.getJavaLine());
String pageParam;
if (page.isNamedAttribute()) {
// If the page for jsp:include was specified via
// jsp:attribute, first generate code to evaluate
// that body.
pageParam =
generateNamedAttributeValue(page.getNamedAttributeNode());
} else {
pageParam = attributeValue(page, false, String.class);
}
// If any of the params have their values specified by
// jsp:attribute, prepare those values first.
Node jspBody = findJspBody(n);
if (jspBody != null) {
prepareParams(jspBody);
} else {
prepareParams(n);
}
out.printin(
"org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "
+ pageParam);
printParams(n, pageParam, page.isLiteral());
out.println(", out, " + isFlush + ");");
n.setEndJavaLine(out.getJavaLine());
}
/**
* Scans through all child nodes of the given parent for
* subelements. For each element, if its value
* is specified via a Named Attribute (),
* generate the code to evaluate those bodies first.
*
* If parent is null, simply returns.
*/
private void prepareParams(Node parent) throws JasperException {
if (parent == null)
return;
Node.Nodes subelements = parent.getBody();
if (subelements != null) {
for (int i = 0; i < subelements.size(); i++) {
Node n = subelements.getNode(i);
if (n instanceof Node.ParamAction) {
Node.Nodes paramSubElements = n.getBody();
for (int j = 0;
(paramSubElements != null)
&& (j < paramSubElements.size());
j++) {
Node m = paramSubElements.getNode(j);
if (m instanceof Node.NamedAttribute) {
generateNamedAttributeValue(
(Node.NamedAttribute)m);
}
}
}
}
}
}
/**
* Finds the subelement of the given parent node.
* If not found, null is returned.
*/
private Node.JspBody findJspBody(Node parent) throws JasperException {
Node.JspBody result = null;
Node.Nodes subelements = parent.getBody();
for (int i = 0;
(subelements != null) && (i < subelements.size());
i++) {
Node n = subelements.getNode(i);
if (n instanceof Node.JspBody) {
result = (Node.JspBody)n;
break;
}
}
return result;
}
public void visit(Node.ForwardAction n) throws JasperException {
Node.JspAttribute page = n.getPage();
n.setBeginJavaLine(out.getJavaLine());
out.printil("if (true) {"); // So that javac won't complain about
out.pushIndent(); // codes after "return"
String pageParam;
if (page.isNamedAttribute()) {
// If the page for jsp:forward was specified via
// jsp:attribute, first generate code to evaluate
// that body.
pageParam =
generateNamedAttributeValue(page.getNamedAttributeNode());
} else {
pageParam = attributeValue(page, false, String.class);
}
// If any of the params have their values specified by
// jsp:attribute, prepare those values first.
Node jspBody = findJspBody(n);
if (jspBody != null) {
prepareParams(jspBody);
} else {
prepareParams(n);
}
out.printin("_jspx_page_context.forward(");
out.print(pageParam);
printParams(n, pageParam, page.isLiteral());
out.println(");");
if (isTagFile || isFragment) {
out.printil("throw new SkipPageException();");
} else {
out.printil((methodNesting > 0) ? "return true;" : "return;");
}
out.popIndent();
out.printil("}");
n.setEndJavaLine(out.getJavaLine());
// XXX Not sure if we can eliminate dead codes after this.
}
public void visit(Node.GetProperty n) throws JasperException {
String name = n.getTextAttribute("name");
String property = n.getTextAttribute("property");
n.setBeginJavaLine(out.getJavaLine());
if (beanInfo.checkVariable(name)) {
// Bean is defined using useBean, introspect at compile time
Class bean = beanInfo.getBeanType(name);
String beanName = JspUtil.getCanonicalName(bean);
java.lang.reflect.Method meth =
JspRuntimeLibrary.getReadMethod(bean, property);
String methodName = meth.getName();
out.printil(
"out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString("
+ "((("
+ beanName
+ ")_jspx_page_context.findAttribute("
+ "\""
+ name
+ "\"))."
+ methodName
+ "())));");
} else {
// The object could be a custom action with an associated
// VariableInfo entry for this name.
// Get the class name and then introspect at runtime.
out.printil(
"out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString"
+ "(org.apache.jasper.runtime.JspRuntimeLibrary.handleGetProperty"
+ "(_jspx_page_context.findAttribute(\""
+ name
+ "\"), \""
+ property
+ "\")));");
}
n.setEndJavaLine(out.getJavaLine());
}
public void visit(Node.SetProperty n) throws JasperException {
String name = n.getTextAttribute("name");
String property = n.getTextAttribute("property");
String param = n.getTextAttribute("param");
Node.JspAttribute value = n.getValue();
n.setBeginJavaLine(out.getJavaLine());
if ("*".equals(property)) {
out.printil(
"org.apache.jasper.runtime.JspRuntimeLibrary.introspect("
+ "_jspx_page_context.findAttribute("
+ "\""
+ name
+ "\"), request);");
} else if (value == null) {
if (param == null)
param = property; // default to same as property
out.printil(
"org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper("
+ "_jspx_page_context.findAttribute(\""
+ name
+ "\"), \""
+ property
+ "\", request.getParameter(\""
+ param
+ "\"), "
+ "request, \""
+ param
+ "\", false);");
} else if (value.isExpression()) {
out.printil(
"org.apache.jasper.runtime.JspRuntimeLibrary.handleSetProperty("
+ "_jspx_page_context.findAttribute(\""
+ name
+ "\"), \""
+ property
+ "\",");
out.print(attributeValue(value, false, null));
out.println(");");
} else if (value.isELInterpreterInput()) {
// We've got to resolve the very call to the interpreter
// at runtime since we don't know what type to expect
// in the general case; we thus can't hard-wire the call
// into the generated code. (XXX We could, however,
// optimize the case where the bean is exposed with
// , much as the code here does for
// getProperty.)
out.printil(
"org.apache.jasper.runtime.JspRuntimeLibrary.handleSetPropertyExpression("
+ "_jspx_page_context.findAttribute(\""
+ name
+ "\"), \""
+ property
+ "\", "
+ quote(value.getValue())
+ ", "
+ "_jspx_page_context, "
+ value.getEL().getMapName()
+ ");");
} else if (value.isNamedAttribute()) {
// If the value for setProperty was specified via
// jsp:attribute, first generate code to evaluate
// that body.
String valueVarName =
generateNamedAttributeValue(value.getNamedAttributeNode());
out.printil(
"org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper("
+ "_jspx_page_context.findAttribute(\""
+ name
+ "\"), \""
+ property
+ "\", "
+ valueVarName
+ ", null, null, false);");
} else {
out.printin(
"org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper("
+ "_jspx_page_context.findAttribute(\""
+ name
+ "\"), \""
+ property
+ "\", ");
out.print(attributeValue(value, false, null));
out.println(", null, null, false);");
}
n.setEndJavaLine(out.getJavaLine());
}
public void visit(Node.UseBean n) throws JasperException {
String name = n.getTextAttribute("id");
String scope = n.getTextAttribute("scope");
String klass = n.getTextAttribute("class");
String type = n.getTextAttribute("type");
Node.JspAttribute beanName = n.getBeanName();
// If "class" is specified, try an instantiation at compile time
boolean generateNew = false;
String canonicalName = null; // Canonical name for klass
if (klass != null) {
try {
Class> bean = ctxt.getClassLoader().loadClass(klass);
if (klass.indexOf('$') >= 0) {
// Obtain the canonical type name
canonicalName = JspUtil.getCanonicalName(bean);
} else {
canonicalName = klass;
}
int modifiers = bean.getModifiers();
if (!Modifier.isPublic(modifiers) ||
Modifier.isInterface(modifiers) ||
Modifier.isAbstract(modifiers)) {
throw new Exception("Invalid bean class modifier");
}
// Check that there is a 0 arg constructor
bean.getConstructor(new Class[]{});
// At compile time, we have determined that the bean class
// exists, with a public zero constructor, new() can be
// used for bean instantiation.
generateNew = true;
} catch (Exception e) {
// Cannot instantiate the specified class, either a
// compilation error or a runtime error will be raised,
// depending on a compiler flag.
if (ctxt.getOptions().getErrorOnUseBeanInvalidClassAttribute()) {
err.jspError(n, "jsp.error.invalid.bean", klass);
}
if (canonicalName == null) {
// Doing our best here to get a canonical name
// from the binary name, should work 99.99% of time.
canonicalName = klass.replace('$','.');
}
}
if (type == null) {
// if type is unspecified, use "class" as type of bean
type = canonicalName;
}
}
String scopename = "PageContext.PAGE_SCOPE"; // Default to page
String lock = "_jspx_page_context";
if ("request".equals(scope)) {
scopename = "PageContext.REQUEST_SCOPE";
lock = "request";
} else if ("session".equals(scope)) {
scopename = "PageContext.SESSION_SCOPE";
lock = "session";
} else if ("application".equals(scope)) {
scopename = "PageContext.APPLICATION_SCOPE";
lock = "application";
}
n.setBeginJavaLine(out.getJavaLine());
// Declare bean
out.printin(type);
out.print(' ');
out.print(name);
out.println(" = null;");
/*
* Use synchonized block only if 'klass' or 'beanName' is defined.
* In all other cases, bean must be located in the given scope.
*/
// START S1AS 4642094
if (klass != null || beanName != null) {
// END S1AS 4642094
out.printin("synchronized (");
out.print(lock);
out.println(") {");
out.pushIndent();
// START S1AS 4642094
}
// END S1AS 4642094
// Locate bean from context
out.printin(name);
out.print(" = (");
out.print(type);
out.print(") _jspx_page_context.getAttribute(");
out.print(quote(name));
out.print(", ");
out.print(scopename);
out.println(");");
// Create bean
/*
* Check if bean is alredy there
*/
out.printin("if (");
out.print(name);
out.println(" == null){");
out.pushIndent();
if (klass == null && beanName == null) {
/*
* If both class name and beanName is not specified, the bean
* must be found locally, otherwise it's an error
*/
out.printin(
"throw new java.lang.InstantiationException(\"bean ");
out.print(name);
out.println(" not found within scope\");");
} else {
/*
* Instantiate the bean if it is not in the specified scope.
*/
if (!generateNew) {
String binaryName;
if (beanName != null) {
if (beanName.isNamedAttribute()) {
// If the value for beanName was specified via
// jsp:attribute, first generate code to evaluate
// that body.
binaryName =
generateNamedAttributeValue(
beanName.getNamedAttributeNode());
} else {
binaryName =
attributeValue(beanName, false, String.class);
}
} else {
// Implies klass is not null
binaryName = quote(klass);
}
out.printil("try {");
out.pushIndent();
out.printin(name);
out.print(" = (");
out.print(type);
out.print(") java.beans.Beans.instantiate(");
out.print("this.getClass().getClassLoader(), ");
out.print(binaryName);
out.println(");");
out.popIndent();
/*
* Note: Beans.instantiate throws ClassNotFoundException
* if the bean class is abstract.
*/
out.printil("} catch (ClassNotFoundException exc) {");
out.pushIndent();
out.printil(
"throw new InstantiationException(exc.getMessage());");
out.popIndent();
out.printil("} catch (Exception exc) {");
out.pushIndent();
out.printin("throw new ServletException(");
out.print("\"Cannot create bean of class \" + ");
out.print(binaryName);
out.println(", exc);");
out.popIndent();
out.printil("}"); // close of try
} else {
// Implies klass is not null
// Generate codes to instantiate the bean class
out.printin(name);
out.print(" = new ");
out.print(canonicalName);
out.println("();");
}
/*
* Set attribute for bean in the specified scope
*/
out.printin("_jspx_page_context.setAttribute(");
out.print(quote(name));
out.print(", ");
out.print(name);
out.print(", ");
out.print(scopename);
out.println(");");
// Only visit the body when bean is instantiated
visitBody(n);
}
out.popIndent();
out.printil("}");
// End of lock block
// START S1AS 4642094
if (klass != null || beanName != null) {
// END S1AS 4642094
out.popIndent();
out.printil("}");
// START S1AS 4642094
}
// END S1AS 4642094
n.setEndJavaLine(out.getJavaLine());
}
/**
* @return a string for the form 'attr = "value"'
*/
private String makeAttr(String attr, String value) {
if (value == null)
return "";
return " " + attr + "=\"" + value + '\"';
}
public void visit(Node.PlugIn n) throws JasperException {
/**
* A visitor to handle in a plugin
*/
class ParamVisitor extends Node.Visitor {
private boolean ie;
ParamVisitor(boolean ie) {
this.ie = ie;
}
public void visit(Node.ParamAction n) throws JasperException {
String name = n.getTextAttribute("name");
if (name.equalsIgnoreCase("object"))
name = "java_object";
else if (name.equalsIgnoreCase("type"))
name = "java_type";
n.setBeginJavaLine(out.getJavaLine());
// XXX - Fixed a bug here - value used to be output
// inline, which is only okay if value is not an EL
// expression. Also, key/value pairs for the
// embed tag were not being generated correctly.
// Double check that this is now the correct behavior.
if (ie) {
// We want something of the form
// out.println( "" );
out.printil(
"out.write( \"\" );");
out.printil("out.write(\"\\n\");");
} else {
// We want something of the form
// out.print( " blah=\"" + ... + "\"" );
out.printil(
"out.write( \" "
+ escape(name)
+ "=\\\"\" + "
+ attributeValue(
n.getValue(),
false,
String.class)
+ " + \"\\\"\" );");
}
n.setEndJavaLine(out.getJavaLine());
}
}
String type = n.getTextAttribute("type");
String code = n.getTextAttribute("code");
String name = n.getTextAttribute("name");
Node.JspAttribute height = n.getHeight();
Node.JspAttribute width = n.getWidth();
String hspace = n.getTextAttribute("hspace");
String vspace = n.getTextAttribute("vspace");
String align = n.getTextAttribute("align");
String iepluginurl = n.getTextAttribute("iepluginurl");
String nspluginurl = n.getTextAttribute("nspluginurl");
String codebase = n.getTextAttribute("codebase");
String archive = n.getTextAttribute("archive");
String jreversion = n.getTextAttribute("jreversion");
String widthStr = null;
if (width != null) {
if (width.isNamedAttribute()) {
widthStr =
generateNamedAttributeValue(
width.getNamedAttributeNode());
} else {
widthStr = attributeValue(width, false, String.class);
}
}
String heightStr = null;
if (height != null) {
if (height.isNamedAttribute()) {
heightStr =
generateNamedAttributeValue(
height.getNamedAttributeNode());
} else {
heightStr = attributeValue(height, false, String.class);
}
}
if (iepluginurl == null)
iepluginurl = Constants.IE_PLUGIN_URL;
if (nspluginurl == null)
nspluginurl = Constants.NS_PLUGIN_URL;
n.setBeginJavaLine(out.getJavaLine());
// If any of the params have their values specified by
// jsp:attribute, prepare those values first.
// Look for a params node and prepare its param subelements:
Node.JspBody jspBody = findJspBody(n);
if (jspBody != null) {
Node.Nodes subelements = jspBody.getBody();
if (subelements != null) {
for (int i = 0; i < subelements.size(); i++) {
Node m = subelements.getNode(i);
if (m instanceof Node.ParamsAction) {
prepareParams(m);
break;
}
}
}
}
// XXX - Fixed a bug here - width and height can be set
// dynamically. Double-check if this generation is correct.
// IE style plugin
//