/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jasper.compiler;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TimeZone;
import java.util.Vector;
import javax.el.MethodExpression;
import javax.el.ValueExpression;
import javax.servlet.jsp.tagext.TagAttributeInfo;
import javax.servlet.jsp.tagext.TagInfo;
import javax.servlet.jsp.tagext.TagVariableInfo;
import javax.servlet.jsp.tagext.VariableInfo;
import org.apache.el.util.JreCompat;
import org.apache.jasper.Constants;
import org.apache.jasper.JasperException;
import org.apache.jasper.JspCompilationContext;
import org.apache.jasper.compiler.Node.ChildInfoBase;
import org.apache.jasper.compiler.Node.NamedAttribute;
import org.apache.jasper.runtime.JspRuntimeLibrary;
import org.xml.sax.Attributes;
/**
* Generate Java source from Nodes
*
* @author Anil K. Vijendran
* @author Danno Ferrin
* @author Mandar Raje
* @author Rajiv Mordani
* @author Pierre Delisle
*
* Tomcat 4.1.x and Tomcat 5:
* @author Kin-man Chung
* @author Jan Luehe
* @author Shawn Bayern
* @author Mark Roth
* @author Denis Benoit
*
* Tomcat 6.x
* @author Jacob Hookom
* @author Remy Maucherat
*/
class Generator {
private static final Class<?>[] OBJECT_CLASS = { Object.class };
private static final String VAR_EXPRESSIONFACTORY =
System.getProperty("org.apache.jasper.compiler.Generator.VAR_EXPRESSIONFACTORY", "_el_expressionfactory");
private static final String VAR_INSTANCEMANAGER =
System.getProperty("org.apache.jasper.compiler.Generator.VAR_INSTANCEMANAGER", "_jsp_instancemanager");
private static final boolean POOL_TAGS_WITH_EXTENDS =
Boolean.getBoolean("org.apache.jasper.compiler.Generator.POOL_TAGS_WITH_EXTENDS");
/* System property that controls if the requirement to have the object
* used in jsp:getProperty action to be previously "introduced"
* to the JSP processor (see JSP.5.3) is enforced.
*/
private static final boolean STRICT_GET_PROPERTY = Boolean.parseBoolean(
System.getProperty(
"org.apache.jasper.compiler.Generator.STRICT_GET_PROPERTY",
"true"));
private final ServletWriter out;
private final ArrayList<GenBuffer> methodsBuffered;
private final FragmentHelperClass fragmentHelperClass;
private final ErrorDispatcher err;
private final BeanRepository beanInfo;
private final Set<String> varInfoNames;
private final JspCompilationContext ctxt;
private final boolean isPoolingEnabled;
private final boolean breakAtLF;
private String jspIdPrefix;
private int jspId;
private final PageInfo pageInfo;
private final Vector<String> tagHandlerPoolNames;
private GenBuffer charArrayBuffer;
private final DateFormat timestampFormat;
private final ELInterpreter elInterpreter;
private final StringInterpreter stringInterpreter;
/**
* @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 - must not be {@code null}
*
* @return escaped string, per Java rule
*/
static String escape(String s) {
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();
}
private String createJspId() {
if (this.jspIdPrefix == null) {
StringBuilder sb = new StringBuilder(32);
String name = ctxt.getServletJavaFileName();
sb.append("jsp_");
// Cast to long to avoid issue with Integer.MIN_VALUE
sb.append(Math.abs((long) name.hashCode()));
sb.append('_');
this.jspIdPrefix = sb.toString();
}
return this.jspIdPrefix + (this.jspId++);
}
/**
* Generates declarations. This includes "info" of the page directive, and
* scriptlet declarations.
*/
private void generateDeclarations(Node.Nodes page) throws JasperException {
class DeclarationVisitor extends Node.Visitor {
private boolean getServletInfoGenerated = false;
/*
* Generates getServletInfo() method that returns the value of the
* page directive's 'info' attribute, if present.
*
* The Validator has already ensured that if the translation unit
* contains more than one page directive with an 'info' attribute,
* their values match.
*/
@Override
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 java.lang.String getServletInfo() {");
out.pushIndent();
out.printin("return ");
out.print(quote(info));
out.println(";");
out.popIndent();
out.printil("}");
out.println();
}
@Override