init
This commit is contained in:
527
java/org/apache/jasper/compiler/AntCompiler.java
Normal file
527
java/org/apache/jasper/compiler/AntCompiler.java
Normal file
File diff suppressed because it is too large
Load Diff
340
java/org/apache/jasper/compiler/AttributeParser.java
Normal file
340
java/org/apache/jasper/compiler/AttributeParser.java
Normal file
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Converts a JSP attribute value into the unquoted equivalent. The attribute
|
||||
* may contain EL expressions, in which case care needs to be taken to avoid any
|
||||
* ambiguities. For example, consider the attribute values "${1+1}" and
|
||||
* "\${1+1}". After unquoting, both appear as "${1+1}" but the first should
|
||||
* evaluate to "2" and the second to "${1+1}". Literal \, $ and # need special
|
||||
* treatment to ensure there is no ambiguity. The JSP attribute unquoting
|
||||
* covers \\, \", \', \$, \#, %\>, <\%, &apos; and &quot;
|
||||
*/
|
||||
public class AttributeParser {
|
||||
|
||||
/**
|
||||
* Parses the provided input String as a JSP attribute and returns an
|
||||
* unquoted value.
|
||||
*
|
||||
* @param input The input.
|
||||
* @param quote The quote character for the attribute or 0 for
|
||||
* scripting expressions.
|
||||
* @param isELIgnored Is expression language being ignored on the page
|
||||
* where the JSP attribute is defined.
|
||||
* @param isDeferredSyntaxAllowedAsLiteral
|
||||
* Are deferred expressions treated as literals?
|
||||
* @param strict Should the rules of JSP.1.6 for escaping of quotes
|
||||
* be strictly applied?
|
||||
* @param quoteAttributeEL Should the rules of JSP.1.6 for escaping in
|
||||
* attributes be applied to EL in attribute values?
|
||||
* @return An unquoted JSP attribute that, if it contains
|
||||
* expression language can be safely passed to the EL
|
||||
* processor without fear of ambiguity.
|
||||
*/
|
||||
public static String getUnquoted(String input, char quote,
|
||||
boolean isELIgnored, boolean isDeferredSyntaxAllowedAsLiteral,
|
||||
boolean strict, boolean quoteAttributeEL) {
|
||||
return new AttributeParser(input, quote, isELIgnored,
|
||||
isDeferredSyntaxAllowedAsLiteral, strict, quoteAttributeEL).getUnquoted();
|
||||
}
|
||||
|
||||
/* The quoted input string. */
|
||||
private final String input;
|
||||
|
||||
/* The quote used for the attribute - null for scripting expressions. */
|
||||
private final char quote;
|
||||
|
||||
/* Is expression language being ignored - affects unquoting. \$ and \# are
|
||||
* treated as literals rather than quoted values. */
|
||||
private final boolean isELIgnored;
|
||||
|
||||
/* Are deferred expression treated as literals */
|
||||
private final boolean isDeferredSyntaxAllowedAsLiteral;
|
||||
|
||||
/* If a quote appears that matches quote, must it always be escaped? See
|
||||
* JSP.1.6.
|
||||
*/
|
||||
private final boolean strict;
|
||||
|
||||
private final boolean quoteAttributeEL;
|
||||
|
||||
/* The type ($ or #) of expression. Literals have a type of null. */
|
||||
private final char type;
|
||||
|
||||
/* The length of the quoted input string. */
|
||||
private final int size;
|
||||
|
||||
/* Tracks the current position of the parser in the input String. */
|
||||
private int i = 0;
|
||||
|
||||
/* Indicates if the last character returned by nextChar() was escaped. */
|
||||
private boolean lastChEscaped = false;
|
||||
|
||||
/* The unquoted result. */
|
||||
private final StringBuilder result;
|
||||
|
||||
|
||||
/**
|
||||
* For test purposes.
|
||||
* @param input
|
||||
* @param quote
|
||||
* @param strict
|
||||
*/
|
||||
private AttributeParser(String input, char quote,
|
||||
boolean isELIgnored, boolean isDeferredSyntaxAllowedAsLiteral,
|
||||
boolean strict, boolean quoteAttributeEL) {
|
||||
this.input = input;
|
||||
this.quote = quote;
|
||||
this.isELIgnored = isELIgnored;
|
||||
this.isDeferredSyntaxAllowedAsLiteral =
|
||||
isDeferredSyntaxAllowedAsLiteral;
|
||||
this.strict = strict;
|
||||
this.quoteAttributeEL = quoteAttributeEL;
|
||||
this.type = getType(input);
|
||||
this.size = input.length();
|
||||
result = new StringBuilder(size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Work through input looking for literals and expressions until the input
|
||||
* has all been read.
|
||||
*/
|
||||
private String getUnquoted() {
|
||||
while (i < size) {
|
||||
parseLiteral();
|
||||
parseEL();
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/*
|
||||
* This method gets the next unquoted character and looks for
|
||||
* - literals that need to be converted for EL processing
|
||||
* \ -> type{'\\'}
|
||||
* $ -> type{'$'}
|
||||
* # -> type{'#'}
|
||||
* - start of EL
|
||||
* ${
|
||||
* #{
|
||||
* Note all the examples above *do not* include the escaping required to use
|
||||
* the values in Java code.
|
||||
*/
|
||||
private void parseLiteral() {
|
||||
boolean foundEL = false;
|
||||
while (i < size && !foundEL) {
|
||||
char ch = nextChar();
|
||||
if (!isELIgnored && ch == '\\') {
|
||||
if (type == 0) {
|
||||
result.append("\\");
|
||||
} else {
|
||||
result.append(type);
|
||||
result.append("{'\\\\'}");
|
||||
}
|
||||
} else if (!isELIgnored && ch == '$' && lastChEscaped){
|
||||
if (type == 0) {
|
||||
result.append("\\$");
|
||||
} else {
|
||||
result.append(type);
|
||||
result.append("{'$'}");
|
||||
}
|
||||
} else if (!isELIgnored && ch == '#' && lastChEscaped){
|
||||
// Note if isDeferredSyntaxAllowedAsLiteral==true, \# will
|
||||
// not be treated as an escape
|
||||
if (type == 0) {
|
||||
result.append("\\#");
|
||||
} else {
|
||||
result.append(type);
|
||||
result.append("{'#'}");
|
||||
}
|
||||
} else if (ch == type){
|
||||
if (i < size) {
|
||||
char next = input.charAt(i);
|
||||
if (next == '{') {
|
||||
foundEL = true;
|
||||
// Move back to start of EL
|
||||
i--;
|
||||
} else {
|
||||
result.append(ch);
|
||||
}
|
||||
} else {
|
||||
result.append(ch);
|
||||
}
|
||||
} else {
|
||||
result.append(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Once inside EL, no need to unquote or convert anything. The EL is
|
||||
* terminated by '}'. The only other valid location for '}' is inside a
|
||||
* StringLiteral. The literals are delimited by '\'' or '\"'. The only other
|
||||
* valid location for '\'' or '\"' is also inside a StringLiteral. A quote
|
||||
* character inside a StringLiteral must be escaped if the same quote
|
||||
* character is used to delimit the StringLiteral.
|
||||
*/
|
||||
private void parseEL() {
|
||||
boolean endEL = false;
|
||||
boolean insideLiteral = false;
|
||||
char literalQuote = 0;
|
||||
while (i < size && !endEL) {
|
||||
char ch;
|
||||
if (quoteAttributeEL) {
|
||||
ch = nextChar();
|
||||
} else {
|
||||
ch = input.charAt(i++);
|
||||
}
|
||||
if (ch == '\'' || ch == '\"') {
|
||||
if (insideLiteral) {
|
||||
if (literalQuote == ch) {
|
||||
insideLiteral = false;
|
||||
}
|
||||
} else {
|
||||
insideLiteral = true;
|
||||
literalQuote = ch;
|
||||
}
|
||||
result.append(ch);
|
||||
} else if (ch == '\\') {
|
||||
result.append(ch);
|
||||
if (insideLiteral && size < i) {
|
||||
if (quoteAttributeEL) {
|
||||
ch = nextChar();
|
||||
} else {
|
||||
ch = input.charAt(i++);
|
||||
}
|
||||
result.append(ch);
|
||||
}
|
||||
} else if (ch == '}') {
|
||||
if (!insideLiteral) {
|
||||
endEL = true;
|
||||
}
|
||||
result.append(ch);
|
||||
} else {
|
||||
result.append(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the next unquoted character and sets the lastChEscaped flag to
|
||||
* indicate if it was quoted/escaped or not.
|
||||
* ' is always unquoted to '
|
||||
* " is always unquoted to "
|
||||
* \" is always unquoted to "
|
||||
* \' is always unquoted to '
|
||||
* \\ is always unquoted to \
|
||||
* \$ is unquoted to $ if EL is not being ignored
|
||||
* \# is unquoted to # if EL is not being ignored
|
||||
* <\% is always unquoted to <%
|
||||
* %\> is always unquoted to %>
|
||||
*/
|
||||
private char nextChar() {
|
||||
lastChEscaped = false;
|
||||
char ch = input.charAt(i);
|
||||
|
||||
if (ch == '&') {
|
||||
if (i + 5 < size && input.charAt(i + 1) == 'a' &&
|
||||
input.charAt(i + 2) == 'p' && input.charAt(i + 3) == 'o' &&
|
||||
input.charAt(i + 4) == 's' && input.charAt(i + 5) == ';') {
|
||||
ch = '\'';
|
||||
i += 6;
|
||||
} else if (i + 5 < size && input.charAt(i + 1) == 'q' &&
|
||||
input.charAt(i + 2) == 'u' && input.charAt(i + 3) == 'o' &&
|
||||
input.charAt(i + 4) == 't' && input.charAt(i + 5) == ';') {
|
||||
ch = '\"';
|
||||
i += 6;
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
} else if (ch == '\\' && i + 1 < size) {
|
||||
ch = input.charAt(i + 1);
|
||||
if (ch == '\\' || ch == '\"' || ch == '\'' ||
|
||||
(!isELIgnored &&
|
||||
(ch == '$' ||
|
||||
(!isDeferredSyntaxAllowedAsLiteral &&
|
||||
ch == '#')))) {
|
||||
i += 2;
|
||||
lastChEscaped = true;
|
||||
} else {
|
||||
ch = '\\';
|
||||
++i;
|
||||
}
|
||||
} else if (ch == '<' && (i + 2 < size) && input.charAt(i + 1) == '\\' &&
|
||||
input.charAt(i + 2) == '%') {
|
||||
// Note this is a hack since nextChar only returns a single char
|
||||
// It is safe since <% does not require special treatment for EL
|
||||
// or for literals
|
||||
result.append('<');
|
||||
i+=3;
|
||||
return '%';
|
||||
} else if (ch == '%' && i + 2 < size && input.charAt(i + 1) == '\\' &&
|
||||
input.charAt(i + 2) == '>') {
|
||||
// Note this is a hack since nextChar only returns a single char
|
||||
// It is safe since %> does not require special treatment for EL
|
||||
// or for literals
|
||||
result.append('%');
|
||||
i+=3;
|
||||
return '>';
|
||||
} else if (ch == quote && strict) {
|
||||
String msg = Localizer.getMessage("jsp.error.attribute.noescape",
|
||||
input, ""+ quote);
|
||||
throw new IllegalArgumentException(msg);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determines the type of expression by looking for the first unquoted ${
|
||||
* or #{.
|
||||
*/
|
||||
private char getType(String value) {
|
||||
if (value == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isELIgnored) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
int len = value.length();
|
||||
char current;
|
||||
|
||||
while (j < len) {
|
||||
current = value.charAt(j);
|
||||
if (current == '\\') {
|
||||
// Escape character - skip a character
|
||||
j++;
|
||||
} else if (current == '#' && !isDeferredSyntaxAllowedAsLiteral) {
|
||||
if (j < (len -1) && value.charAt(j + 1) == '{') {
|
||||
return '#';
|
||||
}
|
||||
} else if (current == '$') {
|
||||
if (j < (len - 1) && value.charAt(j + 1) == '{') {
|
||||
return '$';
|
||||
}
|
||||
}
|
||||
j++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
75
java/org/apache/jasper/compiler/BeanRepository.java
Normal file
75
java/org/apache/jasper/compiler/BeanRepository.java
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.util.HashMap;
|
||||
|
||||
import org.apache.jasper.JasperException;
|
||||
|
||||
/**
|
||||
* Repository of {page, request, session, application}-scoped beans
|
||||
*
|
||||
* @author Mandar Raje
|
||||
* @author Remy Maucherat
|
||||
*/
|
||||
public class BeanRepository {
|
||||
|
||||
private final HashMap<String, String> beanTypes;
|
||||
private final ClassLoader loader;
|
||||
private final ErrorDispatcher errDispatcher;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param loader The class loader
|
||||
* @param err The error dispatcher that will be used to report errors
|
||||
*/
|
||||
public BeanRepository(ClassLoader loader, ErrorDispatcher err) {
|
||||
this.loader = loader;
|
||||
this.errDispatcher = err;
|
||||
beanTypes = new HashMap<>();
|
||||
}
|
||||
|
||||
public void addBean(Node.UseBean n, String s, String type, String scope)
|
||||
throws JasperException {
|
||||
|
||||
if (!(scope == null || scope.equals("page") || scope.equals("request")
|
||||
|| scope.equals("session") || scope.equals("application"))) {
|
||||
errDispatcher.jspError(n, "jsp.error.usebean.badScope");
|
||||
}
|
||||
|
||||
beanTypes.put(s, type);
|
||||
}
|
||||
|
||||
public Class<?> getBeanType(String bean)
|
||||
throws JasperException {
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
clazz = loader.loadClass(beanTypes.get(bean));
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new JasperException (ex);
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
|
||||
public boolean checkVariable(String bean) {
|
||||
return beanTypes.containsKey(bean);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
217
java/org/apache/jasper/compiler/Collector.java
Normal file
217
java/org/apache/jasper/compiler/Collector.java
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* 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 org.apache.jasper.JasperException;
|
||||
|
||||
/**
|
||||
* Collect info about the page and nodes, and make them available through
|
||||
* the PageInfo object.
|
||||
*
|
||||
* @author Kin-man Chung
|
||||
* @author Mark Roth
|
||||
*/
|
||||
|
||||
class Collector {
|
||||
|
||||
/**
|
||||
* A visitor for collecting information on the page and the body of
|
||||
* the custom tags.
|
||||
*/
|
||||
private static class CollectVisitor extends Node.Visitor {
|
||||
|
||||
private boolean scriptingElementSeen = false;
|
||||
private boolean usebeanSeen = false;
|
||||
private boolean includeActionSeen = false;
|
||||
private boolean paramActionSeen = false;
|
||||
private boolean setPropertySeen = false;
|
||||
private boolean hasScriptingVars = false;
|
||||
|
||||
@Override
|
||||
public void visit(Node.ParamAction n) throws JasperException {
|
||||
if (n.getValue().isExpression()) {
|
||||
scriptingElementSeen = true;
|
||||
}
|
||||
paramActionSeen = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.IncludeAction n) throws JasperException {
|
||||
if (n.getPage().isExpression()) {
|
||||
scriptingElementSeen = true;
|
||||
}
|
||||
includeActionSeen = true;
|
||||
visitBody(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.ForwardAction n) throws JasperException {
|
||||
if (n.getPage().isExpression()) {
|
||||
scriptingElementSeen = true;
|
||||
}
|
||||
visitBody(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.SetProperty n) throws JasperException {
|
||||
if (n.getValue() != null && n.getValue().isExpression()) {
|
||||
scriptingElementSeen = true;
|
||||
}
|
||||
setPropertySeen = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.UseBean n) throws JasperException {
|
||||
if (n.getBeanName() != null && n.getBeanName().isExpression()) {
|
||||
scriptingElementSeen = true;
|
||||
}
|
||||
usebeanSeen = true;
|
||||
visitBody(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.PlugIn n) throws JasperException {
|
||||
if (n.getHeight() != null && n.getHeight().isExpression()) {
|
||||
scriptingElementSeen = true;
|
||||
}
|
||||
if (n.getWidth() != null && n.getWidth().isExpression()) {
|
||||
scriptingElementSeen = true;
|
||||
}
|
||||
visitBody(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.CustomTag n) throws JasperException {
|
||||
// Check to see what kinds of element we see as child elements
|
||||
checkSeen( n.getChildInfo(), n );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check all child nodes for various elements and update the given
|
||||
* ChildInfo object accordingly. Visits body in the process.
|
||||
*/
|
||||
private void checkSeen( Node.ChildInfo ci, Node n )
|
||||
throws JasperException
|
||||
{
|
||||
// save values collected so far
|
||||
boolean scriptingElementSeenSave = scriptingElementSeen;
|
||||
scriptingElementSeen = false;
|
||||
boolean usebeanSeenSave = usebeanSeen;
|
||||
usebeanSeen = false;
|
||||
boolean includeActionSeenSave = includeActionSeen;
|
||||
includeActionSeen = false;
|
||||
boolean paramActionSeenSave = paramActionSeen;
|
||||
paramActionSeen = false;
|
||||
boolean setPropertySeenSave = setPropertySeen;
|
||||
setPropertySeen = false;
|
||||
boolean hasScriptingVarsSave = hasScriptingVars;
|
||||
hasScriptingVars = false;
|
||||
|
||||
// Scan attribute list for expressions
|
||||
if( n instanceof Node.CustomTag ) {
|
||||
Node.CustomTag ct = (Node.CustomTag)n;
|
||||
Node.JspAttribute[] attrs = ct.getJspAttributes();
|
||||
for (int i = 0; attrs != null && i < attrs.length; i++) {
|
||||
if (attrs[i].isExpression()) {
|
||||
scriptingElementSeen = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
visitBody(n);
|
||||
|
||||
if( (n instanceof Node.CustomTag) && !hasScriptingVars) {
|
||||
Node.CustomTag ct = (Node.CustomTag)n;
|
||||
hasScriptingVars = ct.getVariableInfos().length > 0 ||
|
||||
ct.getTagVariableInfos().length > 0;
|
||||
}
|
||||
|
||||
// Record if the tag element and its body contains any scriptlet.
|
||||
ci.setScriptless(! scriptingElementSeen);
|
||||
ci.setHasUseBean(usebeanSeen);
|
||||
ci.setHasIncludeAction(includeActionSeen);
|
||||
ci.setHasParamAction(paramActionSeen);
|
||||
ci.setHasSetProperty(setPropertySeen);
|
||||
ci.setHasScriptingVars(hasScriptingVars);
|
||||
|
||||
// Propagate value of scriptingElementSeen up.
|
||||
scriptingElementSeen = scriptingElementSeen || scriptingElementSeenSave;
|
||||
usebeanSeen = usebeanSeen || usebeanSeenSave;
|
||||
setPropertySeen = setPropertySeen || setPropertySeenSave;
|
||||
includeActionSeen = includeActionSeen || includeActionSeenSave;
|
||||
paramActionSeen = paramActionSeen || paramActionSeenSave;
|
||||
hasScriptingVars = hasScriptingVars || hasScriptingVarsSave;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.JspElement n) throws JasperException {
|
||||
if (n.getNameAttribute().isExpression())
|
||||
scriptingElementSeen = true;
|
||||
|
||||
Node.JspAttribute[] attrs = n.getJspAttributes();
|
||||
for (int i = 0; i < attrs.length; i++) {
|
||||
if (attrs[i].isExpression()) {
|
||||
scriptingElementSeen = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
visitBody(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.JspBody n) throws JasperException {
|
||||
checkSeen( n.getChildInfo(), n );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.NamedAttribute n) throws JasperException {
|
||||
checkSeen( n.getChildInfo(), n );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.Declaration n) throws JasperException {
|
||||
scriptingElementSeen = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.Expression n) throws JasperException {
|
||||
scriptingElementSeen = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.Scriptlet n) throws JasperException {
|
||||
scriptingElementSeen = true;
|
||||
}
|
||||
|
||||
private void updatePageInfo(PageInfo pageInfo) {
|
||||
pageInfo.setScriptless(! scriptingElementSeen);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void collect(Compiler compiler, Node.Nodes page)
|
||||
throws JasperException {
|
||||
|
||||
CollectVisitor collectVisitor = new CollectVisitor();
|
||||
page.visit(collectVisitor);
|
||||
collectVisitor.updatePageInfo(compiler.getPageInfo());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
607
java/org/apache/jasper/compiler/Compiler.java
Normal file
607
java/org/apache/jasper/compiler/Compiler.java
Normal file
File diff suppressed because it is too large
Load Diff
120
java/org/apache/jasper/compiler/DefaultErrorHandler.java
Normal file
120
java/org/apache/jasper/compiler/DefaultErrorHandler.java
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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 org.apache.jasper.JasperException;
|
||||
|
||||
/**
|
||||
* Default implementation of ErrorHandler interface.
|
||||
*
|
||||
* @author Jan Luehe
|
||||
*/
|
||||
class DefaultErrorHandler implements ErrorHandler {
|
||||
|
||||
/*
|
||||
* Processes the given JSP parse error.
|
||||
*
|
||||
* @param fname Name of the JSP file in which the parse error occurred
|
||||
* @param line Parse error line number
|
||||
* @param column Parse error column number
|
||||
* @param errMsg Parse error message
|
||||
* @param exception Parse exception
|
||||
*/
|
||||
@Override
|
||||
public void jspError(String fname, int line, int column, String errMsg,
|
||||
Exception ex) throws JasperException {
|
||||
throw new JasperException(fname + " (" +
|
||||
Localizer.getMessage("jsp.error.location",
|
||||
Integer.toString(line), Integer.toString(column)) +
|
||||
") " + errMsg, ex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Processes the given JSP parse error.
|
||||
*
|
||||
* @param errMsg Parse error message
|
||||
* @param exception Parse exception
|
||||
*/
|
||||
@Override
|
||||
public void jspError(String errMsg, Exception ex) throws JasperException {
|
||||
throw new JasperException(errMsg, ex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Processes the given javac compilation errors.
|
||||
*
|
||||
* @param details Array of JavacErrorDetail instances corresponding to the
|
||||
* compilation errors
|
||||
*/
|
||||
@Override
|
||||
public void javacError(JavacErrorDetail[] details) throws JasperException {
|
||||
|
||||
if (details == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object[] args = null;
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
for (int i=0; i < details.length; i++) {
|
||||
if (details[i].getJspBeginLineNumber() >= 0) {
|
||||
args = new Object[] {
|
||||
Integer.valueOf(details[i].getJspBeginLineNumber()),
|
||||
details[i].getJspFileName() };
|
||||
buf.append(System.lineSeparator());
|
||||
buf.append(System.lineSeparator());
|
||||
buf.append(Localizer.getMessage("jsp.error.single.line.number",
|
||||
args));
|
||||
buf.append(System.lineSeparator());
|
||||
buf.append(details[i].getErrorMessage());
|
||||
buf.append(System.lineSeparator());
|
||||
buf.append(details[i].getJspExtract());
|
||||
} else {
|
||||
args = new Object[] {
|
||||
Integer.valueOf(details[i].getJavaLineNumber()),
|
||||
details[i].getJavaFileName() };
|
||||
buf.append(System.lineSeparator());
|
||||
buf.append(System.lineSeparator());
|
||||
buf.append(Localizer.getMessage("jsp.error.java.line.number",
|
||||
args));
|
||||
buf.append(System.lineSeparator());
|
||||
buf.append(details[i].getErrorMessage());
|
||||
}
|
||||
}
|
||||
buf.append(System.lineSeparator());
|
||||
buf.append(System.lineSeparator());
|
||||
buf.append("Stacktrace:");
|
||||
throw new JasperException(
|
||||
Localizer.getMessage("jsp.error.unable.compile") + ": " + buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the given javac error report and exception.
|
||||
*
|
||||
* @param errorReport Compilation error report
|
||||
* @param exception Compilation exception
|
||||
*/
|
||||
@Override
|
||||
public void javacError(String errorReport, Exception exception)
|
||||
throws JasperException {
|
||||
|
||||
throw new JasperException(
|
||||
Localizer.getMessage("jsp.error.unable.compile"), exception);
|
||||
}
|
||||
|
||||
}
|
||||
331
java/org/apache/jasper/compiler/ELFunctionMapper.java
Normal file
331
java/org/apache/jasper/compiler/ELFunctionMapper.java
Normal file
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
* 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.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.jsp.tagext.FunctionInfo;
|
||||
|
||||
import org.apache.jasper.Constants;
|
||||
import org.apache.jasper.JasperException;
|
||||
import org.apache.tomcat.util.security.PrivilegedGetTccl;
|
||||
|
||||
/**
|
||||
* This class generates functions mappers for the EL expressions in the page.
|
||||
* Instead of a global mapper, a mapper is used for each call to EL
|
||||
* evaluator, thus avoiding the prefix overlapping and redefinition
|
||||
* issues.
|
||||
*
|
||||
* @author Kin-man Chung
|
||||
*/
|
||||
|
||||
public class ELFunctionMapper {
|
||||
private int currFunc = 0;
|
||||
private StringBuilder ds; // Contains codes to initialize the functions mappers.
|
||||
private StringBuilder ss; // Contains declarations of the functions mappers.
|
||||
|
||||
/**
|
||||
* Creates the functions mappers for all EL expressions in the JSP page.
|
||||
*
|
||||
* @param page The current compilation unit.
|
||||
* @throws JasperException EL error
|
||||
*/
|
||||
public static void map(Node.Nodes page)
|
||||
throws JasperException {
|
||||
|
||||
ELFunctionMapper map = new ELFunctionMapper();
|
||||
map.ds = new StringBuilder();
|
||||
map.ss = new StringBuilder();
|
||||
|
||||
page.visit(map.new ELFunctionVisitor());
|
||||
|
||||
// Append the declarations to the root node
|
||||
String ds = map.ds.toString();
|
||||
if (ds.length() > 0) {
|
||||
Node root = page.getRoot();
|
||||
@SuppressWarnings("unused")
|
||||
Node unused = new Node.Declaration(map.ss.toString(), null, root);
|
||||
unused = new Node.Declaration(
|
||||
"static {\n" + ds + "}\n", null, root);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A visitor for the page. The places where EL is allowed are scanned
|
||||
* for functions, and if found functions mappers are created.
|
||||
*/
|
||||
private class ELFunctionVisitor extends Node.Visitor {
|
||||
|
||||
/**
|
||||
* Use a global name map to facilitate reuse of function maps.
|
||||
* The key used is prefix:function:uri.
|
||||
*/
|
||||
private final HashMap<String, String> gMap = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void visit(Node.ParamAction n) throws JasperException {
|
||||
doMap(n.getValue());
|
||||
visitBody(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.IncludeAction n) throws JasperException {
|
||||
doMap(n.getPage());
|
||||
visitBody(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.ForwardAction n) throws JasperException {
|
||||
doMap(n.getPage());
|
||||
visitBody(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.SetProperty n) throws JasperException {
|
||||
doMap(n.getValue());
|
||||
visitBody(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.UseBean n) throws JasperException {
|
||||
doMap(n.getBeanName());
|
||||
visitBody(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.PlugIn n) throws JasperException {
|
||||
doMap(n.getHeight());
|
||||
doMap(n.getWidth());
|
||||
visitBody(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.JspElement n) throws JasperException {
|
||||
|
||||
Node.JspAttribute[] attrs = n.getJspAttributes();
|
||||
for (int i = 0; attrs != null && i < attrs.length; i++) {
|
||||
doMap(attrs[i]);
|
||||
}
|
||||
doMap(n.getNameAttribute());
|
||||
visitBody(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.UninterpretedTag n) throws JasperException {
|
||||
|
||||
Node.JspAttribute[] attrs = n.getJspAttributes();
|
||||
for (int i = 0; attrs != null && i < attrs.length; i++) {
|
||||
doMap(attrs[i]);
|
||||
}
|
||||
visitBody(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.CustomTag n) throws JasperException {
|
||||
Node.JspAttribute[] attrs = n.getJspAttributes();
|
||||
for (int i = 0; attrs != null && i < attrs.length; i++) {
|
||||
doMap(attrs[i]);
|
||||
}
|
||||
visitBody(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.ELExpression n) throws JasperException {
|
||||
doMap(n.getEL());
|
||||
}
|
||||
|
||||
private void doMap(Node.JspAttribute attr)
|
||||
throws JasperException {
|
||||
if (attr != null) {
|
||||
doMap(attr.getEL());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates function mappers, if needed, from ELNodes
|
||||
*/
|
||||
private void doMap(ELNode.Nodes el)
|
||||
throws JasperException {
|
||||
|
||||
// Only care about functions in ELNode's
|
||||
class Fvisitor extends ELNode.Visitor {
|
||||
private final List<ELNode.Function> funcs = new ArrayList<>();
|
||||
private final Set<String> keySet = new HashSet<>();
|
||||
@Override
|
||||
public void visit(ELNode.Function n) throws JasperException {
|
||||
String key = n.getPrefix() + ":" + n.getName();
|
||||
if (keySet.add(key)) {
|
||||
funcs.add(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (el == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// First locate all unique functions in this EL
|
||||
Fvisitor fv = new Fvisitor();
|
||||
el.visit(fv);
|
||||
List<ELNode.Function> functions = fv.funcs;
|
||||
|
||||
if (functions.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reuse a previous map if possible
|
||||
String decName = matchMap(functions);
|
||||
if (decName != null) {
|
||||
el.setMapName(decName);
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate declaration for the map statically
|
||||
decName = getMapName();
|
||||
ss.append("private static org.apache.jasper.runtime.ProtectedFunctionMapper " + decName + ";\n");
|
||||
|
||||
ds.append(" " + decName + "= ");
|
||||
ds.append("org.apache.jasper.runtime.ProtectedFunctionMapper");
|
||||
|
||||
// Special case if there is only one function in the map
|
||||
String funcMethod = null;
|
||||
if (functions.size() == 1) {
|
||||
funcMethod = ".getMapForFunction";
|
||||
} else {
|
||||
ds.append(".getInstance();\n");
|
||||
funcMethod = " " + decName + ".mapFunction";
|
||||
}
|
||||
|
||||
// Setup arguments for either getMapForFunction or mapFunction
|
||||
for (ELNode.Function f : functions) {
|
||||
FunctionInfo funcInfo = f.getFunctionInfo();
|
||||
String fnQName = f.getPrefix() + ":" + f.getName();
|
||||
if (funcInfo == null) {
|
||||
// Added via Lambda or ImportHandler. EL will expect a
|
||||
// function mapper even if one isn't used so just pass null
|
||||
ds.append(funcMethod + "(null, null, null, null);\n");
|
||||
} else {
|
||||
ds.append(funcMethod + "(\"" + fnQName + "\", " +
|
||||
getCanonicalName(funcInfo.getFunctionClass()) +
|
||||
".class, " + '\"' + f.getMethodName() + "\", " +
|
||||
"new Class[] {");
|
||||
String params[] = f.getParameters();
|
||||
for (int k = 0; k < params.length; k++) {
|
||||
if (k != 0) {
|
||||
ds.append(", ");
|
||||
}
|
||||
int iArray = params[k].indexOf('[');
|
||||
if (iArray < 0) {
|
||||
ds.append(params[k] + ".class");
|
||||
}
|
||||
else {
|
||||
String baseType = params[k].substring(0, iArray);
|
||||
ds.append("java.lang.reflect.Array.newInstance(");
|
||||
ds.append(baseType);
|
||||
ds.append(".class,");
|
||||
|
||||
// Count the number of array dimension
|
||||
int aCount = 0;
|
||||
for (int jj = iArray; jj < params[k].length(); jj++ ) {
|
||||
if (params[k].charAt(jj) == '[') {
|
||||
aCount++;
|
||||
}
|
||||
}
|
||||
if (aCount == 1) {
|
||||
ds.append("0).getClass()");
|
||||
} else {
|
||||
ds.append("new int[" + aCount + "]).getClass()");
|
||||
}
|
||||
}
|
||||
}
|
||||
ds.append("});\n");
|
||||
}
|
||||
// Put the current name in the global function map
|
||||
gMap.put(fnQName + ':' + f.getUri(), decName);
|
||||
}
|
||||
el.setMapName(decName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the name of the function mapper for an EL. Reuse a
|
||||
* previously generated one if possible.
|
||||
* @param functions A List of ELNode.Function instances that
|
||||
* represents the functions in an EL
|
||||
* @return A previous generated function mapper name that can be used
|
||||
* by this EL; null if none found.
|
||||
*/
|
||||
private String matchMap(List<ELNode.Function> functions) {
|
||||
|
||||
String mapName = null;
|
||||
for (ELNode.Function f : functions) {
|
||||
String temName = gMap.get(f.getPrefix() + ':' + f.getName() +
|
||||
':' + f.getUri());
|
||||
if (temName == null) {
|
||||
return null;
|
||||
}
|
||||
if (mapName == null) {
|
||||
mapName = temName;
|
||||
} else if (!temName.equals(mapName)) {
|
||||
// If not all in the previous match, then no match.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return mapName;
|
||||
}
|
||||
|
||||
/*
|
||||
* @return A unique name for a function mapper.
|
||||
*/
|
||||
private String getMapName() {
|
||||
return "_jspx_fnmap_" + currFunc++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a binary class name into a canonical one that can be used
|
||||
* when generating Java source code.
|
||||
*
|
||||
* @param className Binary class name
|
||||
* @return Canonical equivalent
|
||||
*/
|
||||
private String getCanonicalName(String className) throws JasperException {
|
||||
Class<?> clazz;
|
||||
|
||||
ClassLoader tccl;
|
||||
if (Constants.IS_SECURITY_ENABLED) {
|
||||
PrivilegedAction<ClassLoader> pa = new PrivilegedGetTccl();
|
||||
tccl = AccessController.doPrivileged(pa);
|
||||
} else {
|
||||
tccl = Thread.currentThread().getContextClassLoader();
|
||||
}
|
||||
|
||||
try {
|
||||
clazz = Class.forName(className, false, tccl);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new JasperException(e);
|
||||
}
|
||||
return clazz.getCanonicalName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
46
java/org/apache/jasper/compiler/ELInterpreter.java
Normal file
46
java/org/apache/jasper/compiler/ELInterpreter.java
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 org.apache.jasper.JspCompilationContext;
|
||||
|
||||
/**
|
||||
* Defines the interface for the expression language interpreter. This allows
|
||||
* users to provide custom EL interpreter implementations that can optimise
|
||||
* EL processing for an application by , for example, performing code generation
|
||||
* for simple expressions.
|
||||
*/
|
||||
public interface ELInterpreter {
|
||||
|
||||
/**
|
||||
* Returns the string representing the code that will be inserted into the
|
||||
* servlet generated for JSP. The default implementation creates a call to
|
||||
* {@link org.apache.jasper.runtime.PageContextImpl#proprietaryEvaluate(
|
||||
* String, Class, javax.servlet.jsp.PageContext,
|
||||
* org.apache.jasper.runtime.ProtectedFunctionMapper)} but other
|
||||
* implementations may produce more optimised code.
|
||||
* @param context The compilation context
|
||||
* @param isTagFile <code>true</code> if in a tag file rather than a JSP
|
||||
* @param expression a String containing zero or more "${}" expressions
|
||||
* @param expectedType the expected type of the interpreted result
|
||||
* @param fnmapvar Variable pointing to a function map.
|
||||
* @return a String representing a call to the EL interpreter.
|
||||
*/
|
||||
public String interpreterCall(JspCompilationContext context,
|
||||
boolean isTagFile, String expression,
|
||||
Class<?> expectedType, String fnmapvar);
|
||||
}
|
||||
107
java/org/apache/jasper/compiler/ELInterpreterFactory.java
Normal file
107
java/org/apache/jasper/compiler/ELInterpreterFactory.java
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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 javax.servlet.ServletContext;
|
||||
|
||||
import org.apache.jasper.JspCompilationContext;
|
||||
|
||||
/**
|
||||
* Provides {@link ELInterpreter} instances for JSP compilation.
|
||||
*
|
||||
* The search order is as follows:
|
||||
* <ol>
|
||||
* <li>ELInterpreter instance or implementation class name provided as a
|
||||
* ServletContext attribute</li>
|
||||
* <li>Implementation class named in a ServletContext initialisation parameter
|
||||
* </li>
|
||||
* <li>Default implementation</li>
|
||||
* </ol>
|
||||
*/
|
||||
public class ELInterpreterFactory {
|
||||
|
||||
public static final String EL_INTERPRETER_CLASS_NAME =
|
||||
ELInterpreter.class.getName();
|
||||
|
||||
private static final ELInterpreter DEFAULT_INSTANCE =
|
||||
new DefaultELInterpreter();
|
||||
|
||||
|
||||
/**
|
||||
* Obtain the correct EL Interpreter for the given web application.
|
||||
* @param context The Servlet context
|
||||
* @return the EL interpreter
|
||||
* @throws Exception If an error occurs creating the interpreter
|
||||
*/
|
||||
public static ELInterpreter getELInterpreter(ServletContext context)
|
||||
throws Exception {
|
||||
|
||||
ELInterpreter result = null;
|
||||
|
||||
// Search for an implementation
|
||||
// 1. ServletContext attribute (set by application or cached by a
|
||||
// previous call to this method).
|
||||
Object attribute = context.getAttribute(EL_INTERPRETER_CLASS_NAME);
|
||||
if (attribute instanceof ELInterpreter) {
|
||||
return (ELInterpreter) attribute;
|
||||
} else if (attribute instanceof String) {
|
||||
result = createInstance(context, (String) attribute);
|
||||
}
|
||||
|
||||
// 2. ServletContext init parameter
|
||||
if (result == null) {
|
||||
String className =
|
||||
context.getInitParameter(EL_INTERPRETER_CLASS_NAME);
|
||||
if (className != null) {
|
||||
result = createInstance(context, className);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Default
|
||||
if (result == null) {
|
||||
result = DEFAULT_INSTANCE;
|
||||
}
|
||||
|
||||
// Cache the result for next time
|
||||
context.setAttribute(EL_INTERPRETER_CLASS_NAME, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private static ELInterpreter createInstance(ServletContext context,
|
||||
String className) throws Exception {
|
||||
return (ELInterpreter) context.getClassLoader().loadClass(
|
||||
className).getConstructor().newInstance();
|
||||
}
|
||||
|
||||
|
||||
private ELInterpreterFactory() {
|
||||
// Utility class. Hide default constructor.
|
||||
}
|
||||
|
||||
|
||||
public static class DefaultELInterpreter implements ELInterpreter {
|
||||
|
||||
@Override
|
||||
public String interpreterCall(JspCompilationContext context,
|
||||
boolean isTagFile, String expression,
|
||||
Class<?> expectedType, String fnmapvar) {
|
||||
return JspUtil.interpreterCall(isTagFile, expression, expectedType,
|
||||
fnmapvar);
|
||||
}
|
||||
}
|
||||
}
|
||||
270
java/org/apache/jasper/compiler/ELNode.java
Normal file
270
java/org/apache/jasper/compiler/ELNode.java
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* 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.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.jsp.tagext.FunctionInfo;
|
||||
|
||||
import org.apache.jasper.JasperException;
|
||||
|
||||
/**
|
||||
* This class defines internal representation for an EL Expression
|
||||
*
|
||||
* It currently only defines functions. It can be expanded to define
|
||||
* all the components of an EL expression, if need to.
|
||||
*
|
||||
* @author Kin-man Chung
|
||||
*/
|
||||
|
||||
abstract class ELNode {
|
||||
|
||||
public abstract void accept(Visitor v) throws JasperException;
|
||||
|
||||
|
||||
/**
|
||||
* Represents an EL expression: anything in ${ and }.
|
||||
*/
|
||||
public static class Root extends ELNode {
|
||||
|
||||
private final ELNode.Nodes expr;
|
||||
private final char type;
|
||||
|
||||
Root(ELNode.Nodes expr, char type) {
|
||||
this.expr = expr;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor v) throws JasperException {
|
||||
v.visit(this);
|
||||
}
|
||||
|
||||
public ELNode.Nodes getExpression() {
|
||||
return expr;
|
||||
}
|
||||
|
||||
public char getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents text outside of EL expression.
|
||||
*/
|
||||
public static class Text extends ELNode {
|
||||
|
||||
private final String text;
|
||||
|
||||
Text(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor v) throws JasperException {
|
||||
v.visit(this);
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents anything in EL expression, other than functions, including
|
||||
* function arguments etc
|
||||
*/
|
||||
public static class ELText extends ELNode {
|
||||
|
||||
private final String text;
|
||||
|
||||
ELText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor v) throws JasperException {
|
||||
v.visit(this);
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a function
|
||||
* Currently only include the prefix and function name, but not its
|
||||
* arguments.
|
||||
*/
|
||||
public static class Function extends ELNode {
|
||||
|
||||
private final String prefix;
|
||||
private final String name;
|
||||
private final String originalText;
|
||||
private String uri;
|
||||
private FunctionInfo functionInfo;
|
||||
private String methodName;
|
||||
private String[] parameters;
|
||||
|
||||
Function(String prefix, String name, String originalText) {
|
||||
this.prefix = prefix;
|
||||
this.name = name;
|
||||
this.originalText = originalText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor v) throws JasperException {
|
||||
v.visit(this);
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getOriginalText() {
|
||||
return originalText;
|
||||
}
|
||||
|
||||
public void setUri(String uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public String getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
public void setFunctionInfo(FunctionInfo f) {
|
||||
this.functionInfo = f;
|
||||
}
|
||||
|
||||
public FunctionInfo getFunctionInfo() {
|
||||
return functionInfo;
|
||||
}
|
||||
|
||||
public void setMethodName(String methodName) {
|
||||
this.methodName = methodName;
|
||||
}
|
||||
|
||||
public String getMethodName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
public void setParameters(String[] parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
public String[] getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An ordered list of ELNode.
|
||||
*/
|
||||
public static class Nodes {
|
||||
|
||||
/* Name used for creating a map for the functions in this
|
||||
EL expression, for communication to Generator.
|
||||
*/
|
||||
private String mapName = null; // The function map associated this EL
|
||||
private final List<ELNode> list;
|
||||
|
||||
public Nodes() {
|
||||
list = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void add(ELNode en) {
|
||||
list.add(en);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visit the nodes in the list with the supplied visitor.
|
||||
*
|
||||
* @param v The visitor used
|
||||
*
|
||||
* @throws JasperException if an error occurs while visiting a node
|
||||
*/
|
||||
public void visit(Visitor v) throws JasperException {
|
||||
for (ELNode n : list) {
|
||||
n.accept(v);
|
||||
}
|
||||
}
|
||||
|
||||
public Iterator<ELNode> iterator() {
|
||||
return list.iterator();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return list.size() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the expression contains a ${...}
|
||||
*/
|
||||
public boolean containsEL() {
|
||||
for (ELNode n : list) {
|
||||
if (n instanceof Root) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setMapName(String name) {
|
||||
this.mapName = name;
|
||||
}
|
||||
|
||||
public String getMapName() {
|
||||
return mapName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* A visitor class for traversing ELNodes
|
||||
*/
|
||||
public static class Visitor {
|
||||
|
||||
public void visit(Root n) throws JasperException {
|
||||
n.getExpression().visit(this);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void visit(Function n) throws JasperException {
|
||||
// NOOP by default
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void visit(Text n) throws JasperException {
|
||||
// NOOP by default
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void visit(ELText n) throws JasperException {
|
||||
// NOOP by default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
588
java/org/apache/jasper/compiler/ELParser.java
Normal file
588
java/org/apache/jasper/compiler/ELParser.java
Normal file
File diff suppressed because it is too large
Load Diff
217
java/org/apache/jasper/compiler/EncodingDetector.java
Normal file
217
java/org/apache/jasper/compiler/EncodingDetector.java
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* 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.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.xml.stream.XMLInputFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamReader;
|
||||
|
||||
/*
|
||||
* The BoM detection is derived from:
|
||||
* https://svn.us.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/xmlparser/XMLEncodingDetector.java?annotate=1742248
|
||||
*
|
||||
* The prolog is always at least as specific as the BOM therefore any encoding
|
||||
* specified in the prolog should take priority over the BOM.
|
||||
*/
|
||||
class EncodingDetector {
|
||||
|
||||
private static final XMLInputFactory XML_INPUT_FACTORY;
|
||||
static {
|
||||
XML_INPUT_FACTORY = XMLInputFactory.newInstance();
|
||||
}
|
||||
|
||||
private final String encoding;
|
||||
private final int skip;
|
||||
private final boolean encodingSpecifiedInProlog;
|
||||
|
||||
|
||||
/*
|
||||
* TODO: Refactor Jasper InputStream creation and handling so the
|
||||
* InputStream passed to this method is buffered and therefore saves
|
||||
* on multiple opening and re-opening of the same file.
|
||||
*/
|
||||
EncodingDetector(InputStream is) throws IOException {
|
||||
// Keep buffer size to a minimum here. BoM will be no more than 4 bytes
|
||||
// so that is the maximum we need to buffer
|
||||
BufferedInputStream bis = new BufferedInputStream(is, 4);
|
||||
bis.mark(4);
|
||||
|
||||
BomResult bomResult = processBom(bis);
|
||||
|
||||
// Reset the stream back to the start to allow the XML prolog detection
|
||||
// to work. Skip any BoM we discovered.
|
||||
bis.reset();
|
||||
for (int i = 0; i < bomResult.skip; i++) {
|
||||
bis.read();
|
||||
}
|
||||
|
||||
String prologEncoding = getPrologEncoding(bis);
|
||||
if (prologEncoding == null) {
|
||||
encodingSpecifiedInProlog = false;
|
||||
encoding = bomResult.encoding;
|
||||
} else {
|
||||
encodingSpecifiedInProlog = true;
|
||||
encoding = prologEncoding;
|
||||
}
|
||||
skip = bomResult.skip;
|
||||
}
|
||||
|
||||
|
||||
String getEncoding() {
|
||||
return encoding;
|
||||
}
|
||||
|
||||
|
||||
int getSkip() {
|
||||
return skip;
|
||||
}
|
||||
|
||||
|
||||
boolean isEncodingSpecifiedInProlog() {
|
||||
return encodingSpecifiedInProlog;
|
||||
}
|
||||
|
||||
|
||||
private String getPrologEncoding(InputStream stream) {
|
||||
String encoding = null;
|
||||
try {
|
||||
XMLStreamReader xmlStreamReader = XML_INPUT_FACTORY.createXMLStreamReader(stream);
|
||||
encoding = xmlStreamReader.getCharacterEncodingScheme();
|
||||
} catch (XMLStreamException e) {
|
||||
// Ignore
|
||||
}
|
||||
return encoding;
|
||||
}
|
||||
|
||||
|
||||
private BomResult processBom(InputStream stream) {
|
||||
// Read first four bytes (or as many are available) and determine
|
||||
// encoding
|
||||
try {
|
||||
final byte[] b4 = new byte[4];
|
||||
int count = 0;
|
||||
int singleByteRead;
|
||||
while (count < 4) {
|
||||
singleByteRead = stream.read();
|
||||
if (singleByteRead == -1) {
|
||||
break;
|
||||
}
|
||||
b4[count] = (byte) singleByteRead;
|
||||
count++;
|
||||
}
|
||||
|
||||
return parseBom(b4, count);
|
||||
} catch (IOException ioe) {
|
||||
// Failed.
|
||||
return new BomResult("UTF-8", 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private BomResult parseBom(byte[] b4, int count) {
|
||||
|
||||
if (count < 2) {
|
||||
return new BomResult("UTF-8", 0);
|
||||
}
|
||||
|
||||
// UTF-16, with BOM
|
||||
int b0 = b4[0] & 0xFF;
|
||||
int b1 = b4[1] & 0xFF;
|
||||
if (b0 == 0xFE && b1 == 0xFF) {
|
||||
// UTF-16, big-endian
|
||||
return new BomResult("UTF-16BE", 2);
|
||||
}
|
||||
if (b0 == 0xFF && b1 == 0xFE) {
|
||||
// UTF-16, little-endian
|
||||
return new BomResult("UTF-16LE", 2);
|
||||
}
|
||||
|
||||
// default to UTF-8 if we don't have enough bytes to make a
|
||||
// good determination of the encoding
|
||||
if (count < 3) {
|
||||
return new BomResult("UTF-8", 0);
|
||||
}
|
||||
|
||||
// UTF-8 with a BOM
|
||||
int b2 = b4[2] & 0xFF;
|
||||
if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF) {
|
||||
return new BomResult("UTF-8", 3);
|
||||
}
|
||||
|
||||
// default to UTF-8 if we don't have enough bytes to make a
|
||||
// good determination of the encoding
|
||||
if (count < 4) {
|
||||
return new BomResult("UTF-8", 0);
|
||||
}
|
||||
|
||||
// Other encodings. No BOM. Try and ID encoding.
|
||||
int b3 = b4[3] & 0xFF;
|
||||
if (b0 == 0x00 && b1 == 0x00 && b2 == 0x00 && b3 == 0x3C) {
|
||||
// UCS-4, big endian (1234)
|
||||
return new BomResult("ISO-10646-UCS-4", 0);
|
||||
}
|
||||
if (b0 == 0x3C && b1 == 0x00 && b2 == 0x00 && b3 == 0x00) {
|
||||
// UCS-4, little endian (4321)
|
||||
return new BomResult("ISO-10646-UCS-4", 0);
|
||||
}
|
||||
if (b0 == 0x00 && b1 == 0x00 && b2 == 0x3C && b3 == 0x00) {
|
||||
// UCS-4, unusual octet order (2143)
|
||||
// REVISIT: What should this be?
|
||||
return new BomResult("ISO-10646-UCS-4", 0);
|
||||
}
|
||||
if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x00) {
|
||||
// UCS-4, unusual octet order (3412)
|
||||
// REVISIT: What should this be?
|
||||
return new BomResult("ISO-10646-UCS-4", 0);
|
||||
}
|
||||
if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F) {
|
||||
// UTF-16, big-endian, no BOM
|
||||
// (or could turn out to be UCS-2...
|
||||
// REVISIT: What should this be?
|
||||
return new BomResult("UTF-16BE", 0);
|
||||
}
|
||||
if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00) {
|
||||
// UTF-16, little-endian, no BOM
|
||||
// (or could turn out to be UCS-2...
|
||||
return new BomResult("UTF-16LE", 0);
|
||||
}
|
||||
if (b0 == 0x4C && b1 == 0x6F && b2 == 0xA7 && b3 == 0x94) {
|
||||
// EBCDIC
|
||||
// a la xerces1, return CP037 instead of EBCDIC here
|
||||
return new BomResult("CP037", 0);
|
||||
}
|
||||
|
||||
// default encoding
|
||||
return new BomResult("UTF-8", 0);
|
||||
}
|
||||
|
||||
|
||||
private static class BomResult {
|
||||
|
||||
public final String encoding;
|
||||
public final int skip;
|
||||
|
||||
public BomResult(String encoding, int skip) {
|
||||
this.encoding = encoding;
|
||||
this.skip = skip;
|
||||
}
|
||||
}
|
||||
}
|
||||
507
java/org/apache/jasper/compiler/ErrorDispatcher.java
Normal file
507
java/org/apache/jasper/compiler/ErrorDispatcher.java
Normal file
File diff suppressed because it is too large
Load Diff
77
java/org/apache/jasper/compiler/ErrorHandler.java
Normal file
77
java/org/apache/jasper/compiler/ErrorHandler.java
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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 org.apache.jasper.JasperException;
|
||||
|
||||
/**
|
||||
* Interface for handling JSP parse and javac compilation errors.
|
||||
*
|
||||
* An implementation of this interface may be registered with the
|
||||
* ErrorDispatcher by setting the XXX initialization parameter in the JSP
|
||||
* page compiler and execution servlet in Catalina's web.xml file to the
|
||||
* implementation's fully qualified class name.
|
||||
*
|
||||
* @author Jan Luehe
|
||||
* @author Kin-man Chung
|
||||
*/
|
||||
public interface ErrorHandler {
|
||||
|
||||
/**
|
||||
* Processes the given JSP parse error.
|
||||
*
|
||||
* @param fname Name of the JSP file in which the parse error occurred
|
||||
* @param line Parse error line number
|
||||
* @param column Parse error column number
|
||||
* @param msg Parse error message
|
||||
* @param exception Parse exception
|
||||
* @throws JasperException An error occurred
|
||||
*/
|
||||
public void jspError(String fname, int line, int column, String msg,
|
||||
Exception exception) throws JasperException;
|
||||
|
||||
/**
|
||||
* Processes the given JSP parse error.
|
||||
*
|
||||
* @param msg Parse error message
|
||||
* @param exception Parse exception
|
||||
* @throws JasperException An error occurred
|
||||
*/
|
||||
public void jspError(String msg, Exception exception)
|
||||
throws JasperException;
|
||||
|
||||
/**
|
||||
* Processes the given javac compilation errors.
|
||||
*
|
||||
* @param details Array of JavacErrorDetail instances corresponding to the
|
||||
* compilation errors
|
||||
* @throws JasperException An error occurred
|
||||
*/
|
||||
public void javacError(JavacErrorDetail[] details)
|
||||
throws JasperException;
|
||||
|
||||
/**
|
||||
* Processes the given javac error report and exception.
|
||||
*
|
||||
* @param errorReport Compilation error report
|
||||
* @param exception Compilation exception
|
||||
* @throws JasperException An error occurred
|
||||
*/
|
||||
public void javacError(String errorReport, Exception exception)
|
||||
throws JasperException;
|
||||
}
|
||||
4449
java/org/apache/jasper/compiler/Generator.java
Normal file
4449
java/org/apache/jasper/compiler/Generator.java
Normal file
File diff suppressed because it is too large
Load Diff
206
java/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java
Normal file
206
java/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* 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.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.jsp.tagext.FunctionInfo;
|
||||
import javax.servlet.jsp.tagext.TagFileInfo;
|
||||
import javax.servlet.jsp.tagext.TagInfo;
|
||||
import javax.servlet.jsp.tagext.TagLibraryInfo;
|
||||
|
||||
import org.apache.jasper.Constants;
|
||||
import org.apache.jasper.JasperException;
|
||||
import org.apache.jasper.JspCompilationContext;
|
||||
import org.apache.tomcat.util.descriptor.tld.ImplicitTldRuleSet;
|
||||
import org.apache.tomcat.util.descriptor.tld.TaglibXml;
|
||||
import org.apache.tomcat.util.descriptor.tld.TldParser;
|
||||
import org.apache.tomcat.util.descriptor.tld.TldResourcePath;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Class responsible for generating an implicit tag library containing tag
|
||||
* handlers corresponding to the tag files in "/WEB-INF/tags/" or a
|
||||
* subdirectory of it.
|
||||
*
|
||||
* @author Jan Luehe
|
||||
*/
|
||||
class ImplicitTagLibraryInfo extends TagLibraryInfo {
|
||||
|
||||
private static final String WEB_INF_TAGS = "/WEB-INF/tags";
|
||||
private static final String TAG_FILE_SUFFIX = ".tag";
|
||||
private static final String TAGX_FILE_SUFFIX = ".tagx";
|
||||
private static final String TAGS_SHORTNAME = "tags";
|
||||
private static final String TLIB_VERSION = "1.0";
|
||||
private static final String JSP_VERSION = "2.0";
|
||||
private static final String IMPLICIT_TLD = "implicit.tld";
|
||||
|
||||
// Maps tag names to tag file paths
|
||||
private final Hashtable<String,String> tagFileMap;
|
||||
|
||||
private final ParserController pc;
|
||||
private final PageInfo pi;
|
||||
private final Vector<TagFileInfo> vec;
|
||||
|
||||
|
||||
public ImplicitTagLibraryInfo(JspCompilationContext ctxt,
|
||||
ParserController pc,
|
||||
PageInfo pi,
|
||||
String prefix,
|
||||
String tagdir,
|
||||
ErrorDispatcher err) throws JasperException {
|
||||
super(prefix, null);
|
||||
this.pc = pc;
|
||||
this.pi = pi;
|
||||
this.tagFileMap = new Hashtable<>();
|
||||
this.vec = new Vector<>();
|
||||
|
||||
// Implicit tag libraries have no functions:
|
||||
this.functions = new FunctionInfo[0];
|
||||
|
||||
tlibversion = TLIB_VERSION;
|
||||
jspversion = JSP_VERSION;
|
||||
|
||||
if (!tagdir.startsWith(WEB_INF_TAGS)) {
|
||||
err.jspError("jsp.error.invalid.tagdir", tagdir);
|
||||
}
|
||||
|
||||
// Determine the value of the <short-name> subelement of the
|
||||
// "imaginary" <taglib> element
|
||||
if (tagdir.equals(WEB_INF_TAGS)
|
||||
|| tagdir.equals( WEB_INF_TAGS + "/")) {
|
||||
shortname = TAGS_SHORTNAME;
|
||||
} else {
|
||||
shortname = tagdir.substring(WEB_INF_TAGS.length());
|
||||
shortname = shortname.replace('/', '-');
|
||||
}
|
||||
|
||||
// Populate mapping of tag names to tag file paths
|
||||
Set<String> dirList = ctxt.getResourcePaths(tagdir);
|
||||
if (dirList != null) {
|
||||
for (String path : dirList) {
|
||||
if (path.endsWith(TAG_FILE_SUFFIX)
|
||||
|| path.endsWith(TAGX_FILE_SUFFIX)) {
|
||||
/*
|
||||
* Use the filename of the tag file, without the .tag or
|
||||
* .tagx extension, respectively, as the <name> subelement
|
||||
* of the "imaginary" <tag-file> element
|
||||
*/
|
||||
String suffix = path.endsWith(TAG_FILE_SUFFIX) ?
|
||||
TAG_FILE_SUFFIX : TAGX_FILE_SUFFIX;
|
||||
String tagName = path.substring(path.lastIndexOf('/') + 1);
|
||||
tagName = tagName.substring(0,
|
||||
tagName.lastIndexOf(suffix));
|
||||
tagFileMap.put(tagName, path);
|
||||
} else if (path.endsWith(IMPLICIT_TLD)) {
|
||||
TaglibXml taglibXml;
|
||||
try {
|
||||
URL url = ctxt.getResource(path);
|
||||
TldResourcePath resourcePath = new TldResourcePath(url, path);
|
||||
ServletContext servletContext = ctxt.getServletContext();
|
||||
boolean validate = Boolean.parseBoolean(
|
||||
servletContext.getInitParameter(
|
||||
Constants.XML_VALIDATION_TLD_INIT_PARAM));
|
||||
String blockExternalString = servletContext.getInitParameter(
|
||||
Constants.XML_BLOCK_EXTERNAL_INIT_PARAM);
|
||||
boolean blockExternal;
|
||||
if (blockExternalString == null) {
|
||||
blockExternal = true;
|
||||
} else {
|
||||
blockExternal = Boolean.parseBoolean(blockExternalString);
|
||||
}
|
||||
TldParser parser = new TldParser(true, validate,
|
||||
new ImplicitTldRuleSet(), blockExternal);
|
||||
taglibXml = parser.parse(resourcePath);
|
||||
} catch (IOException | SAXException e) {
|
||||
err.jspError(e);
|
||||
// unreached
|
||||
throw new JasperException(e);
|
||||
}
|
||||
this.tlibversion = taglibXml.getTlibVersion();
|
||||
this.jspversion = taglibXml.getJspVersion();
|
||||
try {
|
||||
double version = Double.parseDouble(this.jspversion);
|
||||
if (version < 2.0) {
|
||||
err.jspError("jsp.error.invalid.implicit.version", path);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
err.jspError("jsp.error.invalid.implicit.version", path);
|
||||
}
|
||||
|
||||
// Add implicit TLD to dependency list
|
||||
if (pi != null) {
|
||||
pi.addDependant(path, ctxt.getLastModified(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the given tag name maps to a tag file path,
|
||||
* and if so, parses the corresponding tag file.
|
||||
*
|
||||
* @return The TagFileInfo corresponding to the given tag name, or null if
|
||||
* the given tag name is not implemented as a tag file
|
||||
*/
|
||||
@Override
|
||||
public TagFileInfo getTagFile(String shortName) {
|
||||
|
||||
TagFileInfo tagFile = super.getTagFile(shortName);
|
||||
if (tagFile == null) {
|
||||
String path = tagFileMap.get(shortName);
|
||||
if (path == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TagInfo tagInfo = null;
|
||||
try {
|
||||
tagInfo = TagFileProcessor.parseTagFileDirectives(pc,
|
||||
shortName,
|
||||
path,
|
||||
null,
|
||||
this);
|
||||
} catch (JasperException je) {
|
||||
throw new RuntimeException(je.toString(), je);
|
||||
}
|
||||
|
||||
tagFile = new TagFileInfo(shortName, path, tagInfo);
|
||||
vec.addElement(tagFile);
|
||||
|
||||
this.tagFiles = new TagFileInfo[vec.size()];
|
||||
vec.copyInto(this.tagFiles);
|
||||
}
|
||||
|
||||
return tagFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagLibraryInfo[] getTagLibraryInfos() {
|
||||
Collection<TagLibraryInfo> coll = pi.getTaglibs();
|
||||
return coll.toArray(new TagLibraryInfo[0]);
|
||||
}
|
||||
|
||||
}
|
||||
570
java/org/apache/jasper/compiler/JDTCompiler.java
Normal file
570
java/org/apache/jasper/compiler/JDTCompiler.java
Normal file
File diff suppressed because it is too large
Load Diff
50
java/org/apache/jasper/compiler/JarScannerFactory.java
Normal file
50
java/org/apache/jasper/compiler/JarScannerFactory.java
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 javax.servlet.ServletContext;
|
||||
|
||||
import org.apache.tomcat.JarScanner;
|
||||
import org.apache.tomcat.util.scan.StandardJarScanner;
|
||||
|
||||
/**
|
||||
* Provide a mechanism for Jasper to obtain a reference to the JarScanner
|
||||
* implementation.
|
||||
*/
|
||||
public class JarScannerFactory {
|
||||
|
||||
private JarScannerFactory() {
|
||||
// Don't want any instances so hide the default constructor.
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the {@link JarScanner} associated with the specified {@link
|
||||
* ServletContext}. It is obtained via a context parameter.
|
||||
* @param ctxt The Servlet context
|
||||
* @return a scanner instance
|
||||
*/
|
||||
public static JarScanner getJarScanner(ServletContext ctxt) {
|
||||
JarScanner jarScanner =
|
||||
(JarScanner) ctxt.getAttribute(JarScanner.class.getName());
|
||||
if (jarScanner == null) {
|
||||
ctxt.log(Localizer.getMessage("jsp.warning.noJarScanner"));
|
||||
jarScanner = new StandardJarScanner();
|
||||
}
|
||||
return jarScanner;
|
||||
}
|
||||
|
||||
}
|
||||
64
java/org/apache/jasper/compiler/JasperTagInfo.java
Normal file
64
java/org/apache/jasper/compiler/JasperTagInfo.java
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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 javax.servlet.jsp.tagext.TagAttributeInfo;
|
||||
import javax.servlet.jsp.tagext.TagExtraInfo;
|
||||
import javax.servlet.jsp.tagext.TagInfo;
|
||||
import javax.servlet.jsp.tagext.TagLibraryInfo;
|
||||
import javax.servlet.jsp.tagext.TagVariableInfo;
|
||||
|
||||
/**
|
||||
* TagInfo extension used by tag handlers that are implemented via tag files.
|
||||
* This class provides access to the name of the Map used to store the
|
||||
* dynamic attribute names and values passed to the custom action invocation.
|
||||
* This information is used by the code generator.
|
||||
*/
|
||||
class JasperTagInfo extends TagInfo {
|
||||
|
||||
private final String dynamicAttrsMapName;
|
||||
|
||||
public JasperTagInfo(String tagName,
|
||||
String tagClassName,
|
||||
String bodyContent,
|
||||
String infoString,
|
||||
TagLibraryInfo taglib,
|
||||
TagExtraInfo tagExtraInfo,
|
||||
TagAttributeInfo[] attributeInfo,
|
||||
String displayName,
|
||||
String smallIcon,
|
||||
String largeIcon,
|
||||
TagVariableInfo[] tvi,
|
||||
String mapName) {
|
||||
|
||||
super(tagName, tagClassName, bodyContent, infoString, taglib,
|
||||
tagExtraInfo, attributeInfo, displayName, smallIcon, largeIcon,
|
||||
tvi);
|
||||
|
||||
this.dynamicAttrsMapName = mapName;
|
||||
}
|
||||
|
||||
public String getDynamicAttributesMapName() {
|
||||
return dynamicAttrsMapName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDynamicAttributes() {
|
||||
return dynamicAttrsMapName != null;
|
||||
}
|
||||
}
|
||||
231
java/org/apache/jasper/compiler/JavacErrorDetail.java
Normal file
231
java/org/apache/jasper/compiler/JavacErrorDetail.java
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* 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.io.BufferedReader;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.jasper.JspCompilationContext;
|
||||
import org.apache.tomcat.Jar;
|
||||
|
||||
/**
|
||||
* Class providing details about a javac compilation error.
|
||||
*
|
||||
* @author Jan Luehe
|
||||
* @author Kin-man Chung
|
||||
*/
|
||||
public class JavacErrorDetail {
|
||||
|
||||
private final String javaFileName;
|
||||
private final int javaLineNum;
|
||||
private String jspFileName;
|
||||
private int jspBeginLineNum;
|
||||
private final StringBuilder errMsg;
|
||||
private String jspExtract = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param javaFileName The name of the Java file in which the
|
||||
* compilation error occurred
|
||||
* @param javaLineNum The compilation error line number
|
||||
* @param errMsg The compilation error message
|
||||
*/
|
||||
public JavacErrorDetail(String javaFileName,
|
||||
int javaLineNum,
|
||||
StringBuilder errMsg) {
|
||||
|
||||
this(javaFileName, javaLineNum, null, -1, errMsg, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param javaFileName The name of the Java file in which the
|
||||
* compilation error occurred
|
||||
* @param javaLineNum The compilation error line number
|
||||
* @param jspFileName The name of the JSP file from which the Java source
|
||||
* file was generated
|
||||
* @param jspBeginLineNum The start line number of the JSP element
|
||||
* responsible for the compilation error
|
||||
* @param errMsg The compilation error message
|
||||
* @param ctxt The compilation context
|
||||
*/
|
||||
public JavacErrorDetail(String javaFileName,
|
||||
int javaLineNum,
|
||||
String jspFileName,
|
||||
int jspBeginLineNum,
|
||||
StringBuilder errMsg,
|
||||
JspCompilationContext ctxt) {
|
||||
|
||||
this.javaFileName = javaFileName;
|
||||
this.javaLineNum = javaLineNum;
|
||||
this.errMsg = errMsg;
|
||||
this.jspFileName = jspFileName;
|
||||
// Note: this.jspBeginLineNum is set at the end of this method as it may
|
||||
// be modified (corrected) during the execution of this method
|
||||
|
||||
if (jspBeginLineNum > 0 && ctxt != null) {
|
||||
InputStream is = null;
|
||||
try {
|
||||
Jar tagJar = ctxt.getTagFileJar();
|
||||
if (tagJar != null) {
|
||||
// Strip leading '/'
|
||||
String entryName = jspFileName.substring(1);
|
||||
is = tagJar.getInputStream(entryName);
|
||||
this.jspFileName = tagJar.getURL(entryName);
|
||||
} else {
|
||||
is = ctxt.getResourceAsStream(jspFileName);
|
||||
}
|
||||
// Read both files in, so we can inspect them
|
||||
String[] jspLines = readFile(is);
|
||||
|
||||
try (FileInputStream fis = new FileInputStream(ctxt.getServletJavaFileName())) {
|
||||
String[] javaLines = readFile(fis);
|
||||
|
||||
if (jspLines.length < jspBeginLineNum) {
|
||||
// Avoid ArrayIndexOutOfBoundsException
|
||||
// Probably bug 48498 but could be some other cause
|
||||
jspExtract = Localizer.getMessage("jsp.error.bug48498");
|
||||
return;
|
||||
}
|
||||
|
||||
// If the line contains the opening of a multi-line scriptlet
|
||||
// block, then the JSP line number we got back is probably
|
||||
// faulty. Scan forward to match the java line...
|
||||
if (jspLines[jspBeginLineNum-1].lastIndexOf("<%") >
|
||||
jspLines[jspBeginLineNum-1].lastIndexOf("%>")) {
|
||||
String javaLine = javaLines[javaLineNum-1].trim();
|
||||
|
||||
for (int i=jspBeginLineNum-1; i<jspLines.length; i++) {
|
||||
if (jspLines[i].indexOf(javaLine) != -1) {
|
||||
// Update jsp line number
|
||||
jspBeginLineNum = i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy out a fragment of JSP to display to the user
|
||||
StringBuilder fragment = new StringBuilder(1024);
|
||||
int startIndex = Math.max(0, jspBeginLineNum-1-3);
|
||||
int endIndex = Math.min(
|
||||
jspLines.length-1, jspBeginLineNum-1+3);
|
||||
|
||||
for (int i=startIndex;i<=endIndex; ++i) {
|
||||
fragment.append(i+1);
|
||||
fragment.append(": ");
|
||||
fragment.append(jspLines[i]);
|
||||
fragment.append(System.lineSeparator());
|
||||
}
|
||||
jspExtract = fragment.toString();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
// Can't read files - ignore
|
||||
} finally {
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException ignore) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.jspBeginLineNum = jspBeginLineNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the Java source file in which the compilation error
|
||||
* occurred.
|
||||
*
|
||||
* @return Java source file name
|
||||
*/
|
||||
public String getJavaFileName() {
|
||||
return this.javaFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the compilation error line number.
|
||||
*
|
||||
* @return Compilation error line number
|
||||
*/
|
||||
public int getJavaLineNumber() {
|
||||
return this.javaLineNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the JSP file from which the Java source file was
|
||||
* generated.
|
||||
*
|
||||
* @return JSP file from which the Java source file was generated.
|
||||
*/
|
||||
public String getJspFileName() {
|
||||
return this.jspFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the start line number (in the JSP file) of the JSP element
|
||||
* responsible for the compilation error.
|
||||
*
|
||||
* @return Start line number of the JSP element responsible for the
|
||||
* compilation error
|
||||
*/
|
||||
public int getJspBeginLineNumber() {
|
||||
return this.jspBeginLineNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the compilation error message.
|
||||
*
|
||||
* @return Compilation error message
|
||||
*/
|
||||
public String getErrorMessage() {
|
||||
return this.errMsg.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the extract of the JSP that corresponds to this message.
|
||||
*
|
||||
* @return Extract of JSP where error occurred
|
||||
*/
|
||||
public String getJspExtract() {
|
||||
return this.jspExtract;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a text file from an input stream into a String[]. Used to read in
|
||||
* the JSP and generated Java file when generating error messages.
|
||||
*/
|
||||
private String[] readFile(InputStream s) throws IOException {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(s));
|
||||
List<String> lines = new ArrayList<>();
|
||||
String line;
|
||||
|
||||
while ( (line = reader.readLine()) != null ) {
|
||||
lines.add(line);
|
||||
}
|
||||
|
||||
return lines.toArray( new String[lines.size()] );
|
||||
}
|
||||
}
|
||||
529
java/org/apache/jasper/compiler/JspConfig.java
Normal file
529
java/org/apache/jasper/compiler/JspConfig.java
Normal file
File diff suppressed because it is too large
Load Diff
1547
java/org/apache/jasper/compiler/JspDocumentParser.java
Normal file
1547
java/org/apache/jasper/compiler/JspDocumentParser.java
Normal file
File diff suppressed because it is too large
Load Diff
643
java/org/apache/jasper/compiler/JspReader.java
Normal file
643
java/org/apache/jasper/compiler/JspReader.java
Normal file
File diff suppressed because it is too large
Load Diff
599
java/org/apache/jasper/compiler/JspRuntimeContext.java
Normal file
599
java/org/apache/jasper/compiler/JspRuntimeContext.java
Normal file
File diff suppressed because it is too large
Load Diff
1005
java/org/apache/jasper/compiler/JspUtil.java
Normal file
1005
java/org/apache/jasper/compiler/JspUtil.java
Normal file
File diff suppressed because it is too large
Load Diff
87
java/org/apache/jasper/compiler/Localizer.java
Normal file
87
java/org/apache/jasper/compiler/Localizer.java
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.text.MessageFormat;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import org.apache.jasper.runtime.ExceptionUtils;
|
||||
|
||||
/**
|
||||
* Class responsible for converting error codes to corresponding localized
|
||||
* error messages.
|
||||
*
|
||||
* @author Jan Luehe
|
||||
*/
|
||||
public class Localizer {
|
||||
|
||||
private static ResourceBundle bundle;
|
||||
|
||||
static {
|
||||
try {
|
||||
bundle = ResourceBundle.getBundle("org.apache.jasper.resources.LocalStrings");
|
||||
} catch (Throwable t) {
|
||||
ExceptionUtils.handleThrowable(t);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the localized error message corresponding to the given error
|
||||
* code.
|
||||
*
|
||||
* If the given error code is not defined in the resource bundle for
|
||||
* localized error messages, it is used as the error message.
|
||||
*
|
||||
* @param errCode Error code to localize
|
||||
*
|
||||
* @return Localized error message
|
||||
*/
|
||||
public static String getMessage(String errCode) {
|
||||
String errMsg = errCode;
|
||||
try {
|
||||
if (bundle != null) {
|
||||
errMsg = bundle.getString(errCode);
|
||||
}
|
||||
} catch (MissingResourceException e) {
|
||||
}
|
||||
return errMsg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the localized error message corresponding to the given error
|
||||
* code.
|
||||
*
|
||||
* If the given error code is not defined in the resource bundle for
|
||||
* localized error messages, it is used as the error message.
|
||||
*
|
||||
* @param errCode Error code to localize
|
||||
* @param args Arguments for parametric replacement
|
||||
*
|
||||
* @return Localized error message
|
||||
*/
|
||||
public static String getMessage(String errCode, Object... args) {
|
||||
String errMsg = getMessage(errCode);
|
||||
|
||||
if (args != null && args.length > 0) {
|
||||
MessageFormat formatter = new MessageFormat(errMsg);
|
||||
errMsg = formatter.format(args);
|
||||
}
|
||||
|
||||
return errMsg;
|
||||
}
|
||||
}
|
||||
145
java/org/apache/jasper/compiler/Mark.java
Normal file
145
java/org/apache/jasper/compiler/Mark.java
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* 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.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
import org.apache.jasper.JspCompilationContext;
|
||||
|
||||
/**
|
||||
* Mark represents a point in the JSP input.
|
||||
*
|
||||
* @author Anil K. Vijendran
|
||||
*/
|
||||
final class Mark {
|
||||
|
||||
// position within current stream
|
||||
int cursor, line, col;
|
||||
|
||||
// current stream
|
||||
char[] stream = null;
|
||||
|
||||
// name of the current file
|
||||
private String fileName;
|
||||
|
||||
private JspCompilationContext ctxt;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param reader JspReader this mark belongs to
|
||||
* @param inStream current stream for this mark
|
||||
* @param name JSP file name
|
||||
*/
|
||||
Mark(JspReader reader, char[] inStream, String name) {
|
||||
this.ctxt = reader.getJspCompilationContext();
|
||||
this.stream = inStream;
|
||||
this.cursor = 0;
|
||||
this.line = 1;
|
||||
this.col = 1;
|
||||
this.fileName = name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Mark(Mark other) {
|
||||
init(other, false);
|
||||
}
|
||||
|
||||
void update(int cursor, int line, int col) {
|
||||
this.cursor = cursor;
|
||||
this.line = line;
|
||||
this.col = col;
|
||||
}
|
||||
|
||||
void init(Mark other, boolean singleFile) {
|
||||
this.cursor = other.cursor;
|
||||
this.line = other.line;
|
||||
this.col = other.col;
|
||||
|
||||
if (!singleFile) {
|
||||
this.ctxt = other.ctxt;
|
||||
this.stream = other.stream;
|
||||
this.fileName = other.fileName;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Mark(JspCompilationContext ctxt, String filename, int line, int col) {
|
||||
this.ctxt = ctxt;
|
||||
this.stream = null;
|
||||
this.cursor = 0;
|
||||
this.line = line;
|
||||
this.col = col;
|
||||
this.fileName = filename;
|
||||
}
|
||||
|
||||
|
||||
public int getLineNumber() {
|
||||
return line;
|
||||
}
|
||||
|
||||
public int getColumnNumber() {
|
||||
return col;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getFile()+"("+line+","+col+")";
|
||||
}
|
||||
|
||||
public String getFile() {
|
||||
return this.fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URL of the resource with which this Mark is associated
|
||||
*
|
||||
* @return URL of the resource with which this Mark is associated
|
||||
*
|
||||
* @exception MalformedURLException if the resource pathname is incorrect
|
||||
*/
|
||||
public URL getURL() throws MalformedURLException {
|
||||
return ctxt.getResource(getFile());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof Mark) {
|
||||
Mark m = (Mark) other;
|
||||
return this.cursor == m.cursor && this.line == m.line && this.col == m.col;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + col;
|
||||
result = prime * result + cursor;
|
||||
result = prime * result + line;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
2597
java/org/apache/jasper/compiler/Node.java
Normal file
2597
java/org/apache/jasper/compiler/Node.java
Normal file
File diff suppressed because it is too large
Load Diff
748
java/org/apache/jasper/compiler/PageDataImpl.java
Normal file
748
java/org/apache/jasper/compiler/PageDataImpl.java
Normal file
File diff suppressed because it is too large
Load Diff
731
java/org/apache/jasper/compiler/PageInfo.java
Normal file
731
java/org/apache/jasper/compiler/PageInfo.java
Normal file
File diff suppressed because it is too large
Load Diff
1813
java/org/apache/jasper/compiler/Parser.java
Normal file
1813
java/org/apache/jasper/compiler/Parser.java
Normal file
File diff suppressed because it is too large
Load Diff
596
java/org/apache/jasper/compiler/ParserController.java
Normal file
596
java/org/apache/jasper/compiler/ParserController.java
Normal file
File diff suppressed because it is too large
Load Diff
157
java/org/apache/jasper/compiler/ScriptingVariabler.java
Normal file
157
java/org/apache/jasper/compiler/ScriptingVariabler.java
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* 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.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.jsp.tagext.TagVariableInfo;
|
||||
import javax.servlet.jsp.tagext.VariableInfo;
|
||||
|
||||
import org.apache.jasper.JasperException;
|
||||
|
||||
/**
|
||||
* Class responsible for determining the scripting variables that every
|
||||
* custom action needs to declare.
|
||||
*
|
||||
* @author Jan Luehe
|
||||
*/
|
||||
class ScriptingVariabler {
|
||||
|
||||
private static final Integer MAX_SCOPE = Integer.valueOf(Integer.MAX_VALUE);
|
||||
|
||||
/*
|
||||
* Assigns an identifier (of type integer) to every custom tag, in order
|
||||
* to help identify, for every custom tag, the scripting variables that it
|
||||
* needs to declare.
|
||||
*/
|
||||
private static class CustomTagCounter extends Node.Visitor {
|
||||
|
||||
private int count;
|
||||
private Node.CustomTag parent;
|
||||
|
||||
@Override
|
||||
public void visit(Node.CustomTag n) throws JasperException {
|
||||
n.setCustomTagParent(parent);
|
||||
Node.CustomTag tmpParent = parent;
|
||||
parent = n;
|
||||
visitBody(n);
|
||||
parent = tmpParent;
|
||||
n.setNumCount(Integer.valueOf(count++));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For every custom tag, determines the scripting variables it needs to
|
||||
* declare.
|
||||
*/
|
||||
private static class ScriptingVariableVisitor extends Node.Visitor {
|
||||
|
||||
private final ErrorDispatcher err;
|
||||
private final Map<String, Integer> scriptVars;
|
||||
|
||||
public ScriptingVariableVisitor(ErrorDispatcher err) {
|
||||
this.err = err;
|
||||
scriptVars = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.CustomTag n) throws JasperException {
|
||||
setScriptingVars(n, VariableInfo.AT_BEGIN);
|
||||
setScriptingVars(n, VariableInfo.NESTED);
|
||||
visitBody(n);
|
||||
setScriptingVars(n, VariableInfo.AT_END);
|
||||
}
|
||||
|
||||
private void setScriptingVars(Node.CustomTag n, int scope)
|
||||
throws JasperException {
|
||||
|
||||
TagVariableInfo[] tagVarInfos = n.getTagVariableInfos();
|
||||
VariableInfo[] varInfos = n.getVariableInfos();
|
||||
if (tagVarInfos.length == 0 && varInfos.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Object> vec = new ArrayList<>();
|
||||
|
||||
Integer ownRange = null;
|
||||
Node.CustomTag parent = n.getCustomTagParent();
|
||||
if (scope == VariableInfo.AT_BEGIN
|
||||
|| scope == VariableInfo.AT_END) {
|
||||
if (parent == null)
|
||||
ownRange = MAX_SCOPE;
|
||||
else
|
||||
ownRange = parent.getNumCount();
|
||||
} else {
|
||||
// NESTED
|
||||
ownRange = n.getNumCount();
|
||||
}
|
||||
|
||||
if (varInfos.length > 0) {
|
||||
for (int i=0; i<varInfos.length; i++) {
|
||||
if (varInfos[i].getScope() != scope
|
||||
|| !varInfos[i].getDeclare()) {
|
||||
continue;
|
||||
}
|
||||
String varName = varInfos[i].getVarName();
|
||||
|
||||
Integer currentRange = scriptVars.get(varName);
|
||||
if (currentRange == null ||
|
||||
ownRange.compareTo(currentRange) > 0) {
|
||||
scriptVars.put(varName, ownRange);
|
||||
vec.add(varInfos[i]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i=0; i<tagVarInfos.length; i++) {
|
||||
if (tagVarInfos[i].getScope() != scope
|
||||
|| !tagVarInfos[i].getDeclare()) {
|
||||
continue;
|
||||
}
|
||||
String varName = tagVarInfos[i].getNameGiven();
|
||||
if (varName == null) {
|
||||
varName = n.getTagData().getAttributeString(
|
||||
tagVarInfos[i].getNameFromAttribute());
|
||||
if (varName == null) {
|
||||
err.jspError(n,
|
||||
"jsp.error.scripting.variable.missing_name",
|
||||
tagVarInfos[i].getNameFromAttribute());
|
||||
}
|
||||
}
|
||||
|
||||
Integer currentRange = scriptVars.get(varName);
|
||||
if (currentRange == null ||
|
||||
ownRange.compareTo(currentRange) > 0) {
|
||||
scriptVars.put(varName, ownRange);
|
||||
vec.add(tagVarInfos[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n.setScriptingVars(vec, scope);
|
||||
}
|
||||
}
|
||||
|
||||
public static void set(Node.Nodes page, ErrorDispatcher err)
|
||||
throws JasperException {
|
||||
page.visit(new CustomTagCounter());
|
||||
page.visit(new ScriptingVariableVisitor(err));
|
||||
}
|
||||
}
|
||||
170
java/org/apache/jasper/compiler/ServletWriter.java
Normal file
170
java/org/apache/jasper/compiler/ServletWriter.java
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* 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.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* This is what is used to generate servlets.
|
||||
*
|
||||
* @author Anil K. Vijendran
|
||||
* @author Kin-man Chung
|
||||
*/
|
||||
public class ServletWriter implements AutoCloseable {
|
||||
|
||||
private static final int TAB_WIDTH = 2;
|
||||
private static final String SPACES = " ";
|
||||
|
||||
/**
|
||||
* Current indent level.
|
||||
*/
|
||||
private int indent = 0;
|
||||
private int virtual_indent = 0;
|
||||
|
||||
/**
|
||||
* The sink writer.
|
||||
*/
|
||||
private final PrintWriter writer;
|
||||
|
||||
/**
|
||||
* Servlet line numbers start from 1.
|
||||
*/
|
||||
private int javaLine = 1;
|
||||
|
||||
|
||||
public ServletWriter(PrintWriter writer) {
|
||||
this.writer = writer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
writer.close();
|
||||
}
|
||||
|
||||
|
||||
// -------------------- Access informations --------------------
|
||||
|
||||
public int getJavaLine() {
|
||||
return javaLine;
|
||||
}
|
||||
|
||||
|
||||
// -------------------- Formatting --------------------
|
||||
|
||||
public void pushIndent() {
|
||||
virtual_indent += TAB_WIDTH;
|
||||
if (virtual_indent >= 0 && virtual_indent <= SPACES.length())
|
||||
indent = virtual_indent;
|
||||
}
|
||||
|
||||
public void popIndent() {
|
||||
virtual_indent -= TAB_WIDTH;
|
||||
if (virtual_indent >= 0 && virtual_indent <= SPACES.length())
|
||||
indent = virtual_indent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the given string followed by '\n'
|
||||
* @param s The string
|
||||
*/
|
||||
public void println(String s) {
|
||||
javaLine++;
|
||||
writer.println(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a '\n'
|
||||
*/
|
||||
public void println() {
|
||||
javaLine++;
|
||||
writer.println("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the current indention
|
||||
*/
|
||||
public void printin() {
|
||||
writer.print(SPACES.substring(0, indent));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the current indention, followed by the given string
|
||||
* @param s The string
|
||||
*/
|
||||
public void printin(String s) {
|
||||
writer.print(SPACES.substring(0, indent));
|
||||
writer.print(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the current indention, and then the string, and a '\n'.
|
||||
* @param s The string
|
||||
*/
|
||||
public void printil(String s) {
|
||||
javaLine++;
|
||||
writer.print(SPACES.substring(0, indent));
|
||||
writer.println(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the given char.
|
||||
*
|
||||
* Use println() to print a '\n'.
|
||||
* @param c The char
|
||||
*/
|
||||
public void print(char c) {
|
||||
writer.print(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the given int.
|
||||
* @param i The int
|
||||
*/
|
||||
public void print(int i) {
|
||||
writer.print(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the given string.
|
||||
*
|
||||
* The string must not contain any '\n', otherwise the line count will be
|
||||
* off.
|
||||
* @param s The string
|
||||
*/
|
||||
public void print(String s) {
|
||||
writer.print(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the given string.
|
||||
*
|
||||
* If the string spans multiple lines, the line count will be adjusted
|
||||
* accordingly.
|
||||
* @param s The string
|
||||
*/
|
||||
public void printMultiLn(String s) {
|
||||
int index = 0;
|
||||
|
||||
// look for hidden newlines inside strings
|
||||
while ((index=s.indexOf('\n',index)) > -1 ) {
|
||||
javaLine++;
|
||||
index++;
|
||||
}
|
||||
|
||||
writer.print(s);
|
||||
}
|
||||
}
|
||||
194
java/org/apache/jasper/compiler/SmapGenerator.java
Normal file
194
java/org/apache/jasper/compiler/SmapGenerator.java
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* 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.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a source map (SMAP), which serves to associate lines
|
||||
* of the input JSP file(s) to lines in the generated servlet in the
|
||||
* final .class file, according to the JSR-045 spec.
|
||||
*
|
||||
* @author Shawn Bayern
|
||||
*/
|
||||
public class SmapGenerator {
|
||||
|
||||
//*********************************************************************
|
||||
// Overview
|
||||
|
||||
/*
|
||||
* The SMAP syntax is reasonably straightforward. The purpose of this
|
||||
* class is currently twofold:
|
||||
* - to provide a simple but low-level Java interface to build
|
||||
* a logical SMAP
|
||||
* - to serialize this logical SMAP for eventual inclusion directly
|
||||
* into a .class file.
|
||||
*/
|
||||
|
||||
|
||||
//*********************************************************************
|
||||
// Private state
|
||||
|
||||
private String outputFileName;
|
||||
private String defaultStratum = "Java";
|
||||
private final List<SmapStratum> strata = new ArrayList<>();
|
||||
private final List<String> embedded = new ArrayList<>();
|
||||
private boolean doEmbedded = true;
|
||||
|
||||
//*********************************************************************
|
||||
// Methods for adding mapping data
|
||||
|
||||
/**
|
||||
* Sets the filename (without path information) for the generated
|
||||
* source file. E.g., "foo$jsp.java".
|
||||
* @param x The file name
|
||||
*/
|
||||
public synchronized void setOutputFileName(String x) {
|
||||
outputFileName = x;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the default and only stratum for the smap.
|
||||
*
|
||||
* @param stratum the SmapStratum object to add
|
||||
*/
|
||||
public synchronized void setStratum(SmapStratum stratum) {
|
||||
addStratum(stratum, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds the given SmapStratum object, representing a Stratum with
|
||||
* logically associated FileSection and LineSection blocks, to
|
||||
* the current SmapGenerator. If <code>defaultStartum</code> is true, this
|
||||
* stratum is made the default stratum, overriding any previously
|
||||
* set default.
|
||||
*
|
||||
* @param stratum the SmapStratum object to add
|
||||
* @param defaultStratum if <code>true</code>, this SmapStratum is
|
||||
* considered to represent the default SMAP stratum unless
|
||||
* overwritten
|
||||
*
|
||||
* @deprecated Use {@link #setStratum(SmapStratum)}
|
||||
*/
|
||||
@Deprecated
|
||||
public synchronized void addStratum(SmapStratum stratum,
|
||||
boolean defaultStratum) {
|
||||
strata.add(stratum);
|
||||
if (defaultStratum)
|
||||
this.defaultStratum = stratum.getStratumName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given string as an embedded SMAP with the given stratum name.
|
||||
*
|
||||
* @param smap the SMAP to embed
|
||||
* @param stratumName the name of the stratum output by the compilation
|
||||
* that produced the <code>smap</code> to be embedded
|
||||
*
|
||||
* @deprecated Unused. This will be removed in Tomcat 9.0.x
|
||||
*/
|
||||
@Deprecated
|
||||
public synchronized void addSmap(String smap, String stratumName) {
|
||||
embedded.add("*O " + stratumName + "\n"
|
||||
+ smap
|
||||
+ "*C " + stratumName + "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructs the SmapGenerator whether to actually print any embedded
|
||||
* SMAPs or not. Intended for situations without an SMAP resolver.
|
||||
*
|
||||
* @param status If <code>false</code>, ignore any embedded SMAPs.
|
||||
*
|
||||
* @deprecated Unused. Will be removed in Tomcat 9.0.x
|
||||
*/
|
||||
@Deprecated
|
||||
public void setDoEmbedded(boolean status) {
|
||||
doEmbedded = status;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
// Methods for serializing the logical SMAP
|
||||
|
||||
public synchronized String getString() {
|
||||
// check state and initialize buffer
|
||||
if (outputFileName == null)
|
||||
throw new IllegalStateException();
|
||||
StringBuilder out = new StringBuilder();
|
||||
|
||||
// start the SMAP
|
||||
out.append("SMAP\n");
|
||||
out.append(outputFileName + '\n');
|
||||
out.append(defaultStratum + '\n');
|
||||
|
||||
// include embedded SMAPs
|
||||
if (doEmbedded) {
|
||||
int nEmbedded = embedded.size();
|
||||
for (int i = 0; i < nEmbedded; i++) {
|
||||
out.append(embedded.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
// print our StratumSections, FileSections, and LineSections
|
||||
int nStrata = strata.size();
|
||||
for (int i = 0; i < nStrata; i++) {
|
||||
SmapStratum s = strata.get(i);
|
||||
out.append(s.getString());
|
||||
}
|
||||
|
||||
// end the SMAP
|
||||
out.append("*E\n");
|
||||
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() { return getString(); }
|
||||
|
||||
//*********************************************************************
|
||||
// For testing (and as an example of use)...
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void main(String args[]) {
|
||||
SmapGenerator g = new SmapGenerator();
|
||||
g.setOutputFileName("foo.java");
|
||||
SmapStratum s = new SmapStratum();
|
||||
s.addFile("foo.jsp");
|
||||
s.addFile("bar.jsp", "/foo/foo/bar.jsp");
|
||||
s.addLineData(1, "foo.jsp", 1, 1, 1);
|
||||
s.addLineData(2, "foo.jsp", 1, 6, 1);
|
||||
s.addLineData(3, "foo.jsp", 2, 10, 5);
|
||||
s.addLineData(20, "bar.jsp", 1, 30, 1);
|
||||
g.addStratum(s, true);
|
||||
System.out.print(g);
|
||||
|
||||
System.out.println("---");
|
||||
|
||||
SmapGenerator embedded = new SmapGenerator();
|
||||
embedded.setOutputFileName("blargh.tier2");
|
||||
s = new SmapStratum("Tier2");
|
||||
s.addFile("1.tier2");
|
||||
s.addLineData(1, "1.tier2", 1, 1, 1);
|
||||
embedded.addStratum(s, true);
|
||||
g.addSmap(embedded.toString(), "JSP");
|
||||
System.out.println(g);
|
||||
}
|
||||
}
|
||||
349
java/org/apache/jasper/compiler/SmapStratum.java
Normal file
349
java/org/apache/jasper/compiler/SmapStratum.java
Normal file
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* 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.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents the line and file mappings associated with a JSR-045
|
||||
* "stratum".
|
||||
*
|
||||
* @author Jayson Falkner
|
||||
* @author Shawn Bayern
|
||||
*/
|
||||
public class SmapStratum {
|
||||
|
||||
//*********************************************************************
|
||||
// Class for storing LineInfo data
|
||||
|
||||
/**
|
||||
* Represents a single LineSection in an SMAP, associated with
|
||||
* a particular stratum.
|
||||
*/
|
||||
private static class LineInfo {
|
||||
private int inputStartLine = -1;
|
||||
private int outputStartLine = -1;
|
||||
private int lineFileID = 0;
|
||||
private int inputLineCount = 1;
|
||||
private int outputLineIncrement = 1;
|
||||
private boolean lineFileIDSet = false;
|
||||
|
||||
public void setInputStartLine(int inputStartLine) {
|
||||
if (inputStartLine < 0)
|
||||
throw new IllegalArgumentException("" + inputStartLine);
|
||||
this.inputStartLine = inputStartLine;
|
||||
}
|
||||
|
||||
public void setOutputStartLine(int outputStartLine) {
|
||||
if (outputStartLine < 0)
|
||||
throw new IllegalArgumentException("" + outputStartLine);
|
||||
this.outputStartLine = outputStartLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets lineFileID. Should be called only when different from
|
||||
* that of prior LineInfo object (in any given context) or 0
|
||||
* if the current LineInfo has no (logical) predecessor.
|
||||
* <code>LineInfo</code> will print this file number no matter what.
|
||||
*
|
||||
* @param lineFileID The new line file ID
|
||||
*/
|
||||
public void setLineFileID(int lineFileID) {
|
||||
if (lineFileID < 0)
|
||||
throw new IllegalArgumentException("" + lineFileID);
|
||||
this.lineFileID = lineFileID;
|
||||
this.lineFileIDSet = true;
|
||||
}
|
||||
|
||||
public void setInputLineCount(int inputLineCount) {
|
||||
if (inputLineCount < 0)
|
||||
throw new IllegalArgumentException("" + inputLineCount);
|
||||
this.inputLineCount = inputLineCount;
|
||||
}
|
||||
|
||||
public void setOutputLineIncrement(int outputLineIncrement) {
|
||||
if (outputLineIncrement < 0)
|
||||
throw new IllegalArgumentException("" + outputLineIncrement);
|
||||
this.outputLineIncrement = outputLineIncrement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current LineInfo as a String, print all values only when
|
||||
* appropriate (but LineInfoID if and only if it's been
|
||||
* specified, as its necessity is sensitive to context).
|
||||
*/
|
||||
public String getString() {
|
||||
if (inputStartLine == -1 || outputStartLine == -1)
|
||||
throw new IllegalStateException();
|
||||
StringBuilder out = new StringBuilder();
|
||||
out.append(inputStartLine);
|
||||
if (lineFileIDSet)
|
||||
out.append("#" + lineFileID);
|
||||
if (inputLineCount != 1)
|
||||
out.append("," + inputLineCount);
|
||||
out.append(":" + outputStartLine);
|
||||
if (outputLineIncrement != 1)
|
||||
out.append("," + outputLineIncrement);
|
||||
out.append('\n');
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getString();
|
||||
}
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
// Private state
|
||||
|
||||
private final String stratumName;
|
||||
private final List<String> fileNameList;
|
||||
private final List<String> filePathList;
|
||||
private final List<LineInfo> lineData;
|
||||
private int lastFileID;
|
||||
|
||||
//*********************************************************************
|
||||
// Constructor
|
||||
|
||||
/**
|
||||
* Constructs a new SmapStratum object with the stratum name JSP.
|
||||
*/
|
||||
public SmapStratum() {
|
||||
this("JSP");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new SmapStratum object for the given stratum name
|
||||
* (e.g., JSP).
|
||||
*
|
||||
* @param stratumName the name of the stratum (e.g., JSP)
|
||||
*
|
||||
* @deprecated Use the no-arg constructor
|
||||
*/
|
||||
@Deprecated
|
||||
public SmapStratum(String stratumName) {
|
||||
this.stratumName = stratumName;
|
||||
fileNameList = new ArrayList<>();
|
||||
filePathList = new ArrayList<>();
|
||||
lineData = new ArrayList<>();
|
||||
lastFileID = 0;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
// Methods to add mapping information
|
||||
|
||||
/**
|
||||
* Adds record of a new file, by filename.
|
||||
*
|
||||
* @param filename the filename to add, unqualified by path.
|
||||
*/
|
||||
public void addFile(String filename) {
|
||||
addFile(filename, filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds record of a new file, by filename and path. The path
|
||||
* may be relative to a source compilation path.
|
||||
*
|
||||
* @param filename the filename to add, unqualified by path
|
||||
* @param filePath the path for the filename, potentially relative
|
||||
* to a source compilation path
|
||||
*/
|
||||
public void addFile(String filename, String filePath) {
|
||||
int pathIndex = filePathList.indexOf(filePath);
|
||||
if (pathIndex == -1) {
|
||||
fileNameList.add(filename);
|
||||
filePathList.add(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines consecutive LineInfos wherever possible
|
||||
*/
|
||||
public void optimizeLineSection() {
|
||||
|
||||
/* Some debugging code
|
||||
for (int i = 0; i < lineData.size(); i++) {
|
||||
LineInfo li = (LineInfo)lineData.get(i);
|
||||
System.out.print(li.toString());
|
||||
}
|
||||
*/
|
||||
//Incorporate each LineInfo into the previous LineInfo's
|
||||
//outputLineIncrement, if possible
|
||||
int i = 0;
|
||||
while (i < lineData.size() - 1) {
|
||||
LineInfo li = lineData.get(i);
|
||||
LineInfo liNext = lineData.get(i + 1);
|
||||
if (!liNext.lineFileIDSet
|
||||
&& liNext.inputStartLine == li.inputStartLine
|
||||
&& liNext.inputLineCount == 1
|
||||
&& li.inputLineCount == 1
|
||||
&& liNext.outputStartLine
|
||||
== li.outputStartLine
|
||||
+ li.inputLineCount * li.outputLineIncrement) {
|
||||
li.setOutputLineIncrement(
|
||||
liNext.outputStartLine
|
||||
- li.outputStartLine
|
||||
+ liNext.outputLineIncrement);
|
||||
lineData.remove(i + 1);
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
//Incorporate each LineInfo into the previous LineInfo's
|
||||
//inputLineCount, if possible
|
||||
i = 0;
|
||||
while (i < lineData.size() - 1) {
|
||||
LineInfo li = lineData.get(i);
|
||||
LineInfo liNext = lineData.get(i + 1);
|
||||
if (!liNext.lineFileIDSet
|
||||
&& liNext.inputStartLine == li.inputStartLine + li.inputLineCount
|
||||
&& liNext.outputLineIncrement == li.outputLineIncrement
|
||||
&& liNext.outputStartLine
|
||||
== li.outputStartLine
|
||||
+ li.inputLineCount * li.outputLineIncrement) {
|
||||
li.setInputLineCount(li.inputLineCount + liNext.inputLineCount);
|
||||
lineData.remove(i + 1);
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds complete information about a simple line mapping. Specify
|
||||
* all the fields in this method; the back-end machinery takes care
|
||||
* of printing only those that are necessary in the final SMAP.
|
||||
* (My view is that fields are optional primarily for spatial efficiency,
|
||||
* not for programmer convenience. Could always add utility methods
|
||||
* later.)
|
||||
*
|
||||
* @param inputStartLine starting line in the source file
|
||||
* (SMAP <code>InputStartLine</code>)
|
||||
* @param inputFileName the filepath (or name) from which the input comes
|
||||
* (yields SMAP <code>LineFileID</code>) Use unqualified names
|
||||
* carefully, and only when they uniquely identify a file.
|
||||
* @param inputLineCount the number of lines in the input to map
|
||||
* (SMAP <code>LineFileCount</code>)
|
||||
* @param outputStartLine starting line in the output file
|
||||
* (SMAP <code>OutputStartLine</code>)
|
||||
* @param outputLineIncrement number of output lines to map to each
|
||||
* input line (SMAP <code>OutputLineIncrement</code>). <i>Given the
|
||||
* fact that the name starts with "output", I continuously have
|
||||
* the subconscious urge to call this field
|
||||
* <code>OutputLineExcrement</code>.</i>
|
||||
*/
|
||||
public void addLineData(
|
||||
int inputStartLine,
|
||||
String inputFileName,
|
||||
int inputLineCount,
|
||||
int outputStartLine,
|
||||
int outputLineIncrement) {
|
||||
// check the input - what are you doing here??
|
||||
int fileIndex = filePathList.indexOf(inputFileName);
|
||||
if (fileIndex == -1) // still
|
||||
throw new IllegalArgumentException(
|
||||
"inputFileName: " + inputFileName);
|
||||
|
||||
//Jasper incorrectly SMAPs certain Nodes, giving them an
|
||||
//outputStartLine of 0. This can cause a fatal error in
|
||||
//optimizeLineSection, making it impossible for Jasper to
|
||||
//compile the JSP. Until we can fix the underlying
|
||||
//SMAPping problem, we simply ignore the flawed SMAP entries.
|
||||
if (outputStartLine == 0)
|
||||
return;
|
||||
|
||||
// build the LineInfo
|
||||
LineInfo li = new LineInfo();
|
||||
li.setInputStartLine(inputStartLine);
|
||||
li.setInputLineCount(inputLineCount);
|
||||
li.setOutputStartLine(outputStartLine);
|
||||
li.setOutputLineIncrement(outputLineIncrement);
|
||||
if (fileIndex != lastFileID)
|
||||
li.setLineFileID(fileIndex);
|
||||
lastFileID = fileIndex;
|
||||
|
||||
// save it
|
||||
lineData.add(li);
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
// Methods to retrieve information
|
||||
|
||||
/**
|
||||
* @return the name of the stratum.
|
||||
*
|
||||
* @deprecated Unused. This will be removed in Tomcat 9.0.x
|
||||
*/
|
||||
@Deprecated
|
||||
public String getStratumName() {
|
||||
return stratumName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the given stratum as a String: a StratumSection,
|
||||
* followed by at least one FileSection and at least one LineSection.
|
||||
*/
|
||||
public String getString() {
|
||||
// check state and initialize buffer
|
||||
if (fileNameList.size() == 0 || lineData.size() == 0)
|
||||
return null;
|
||||
|
||||
StringBuilder out = new StringBuilder();
|
||||
|
||||
// print StratumSection
|
||||
out.append("*S " + stratumName + "\n");
|
||||
|
||||
// print FileSection
|
||||
out.append("*F\n");
|
||||
int bound = fileNameList.size();
|
||||
for (int i = 0; i < bound; i++) {
|
||||
if (filePathList.get(i) != null) {
|
||||
out.append("+ " + i + " " + fileNameList.get(i) + "\n");
|
||||
// Source paths must be relative, not absolute, so we
|
||||
// remove the leading "/", if one exists.
|
||||
String filePath = filePathList.get(i);
|
||||
if (filePath.startsWith("/")) {
|
||||
filePath = filePath.substring(1);
|
||||
}
|
||||
out.append(filePath + "\n");
|
||||
} else {
|
||||
out.append(i + " " + fileNameList.get(i) + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
// print LineSection
|
||||
out.append("*L\n");
|
||||
bound = lineData.size();
|
||||
for (int i = 0; i < bound; i++) {
|
||||
LineInfo li = lineData.get(i);
|
||||
out.append(li.getString());
|
||||
}
|
||||
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getString();
|
||||
}
|
||||
|
||||
}
|
||||
713
java/org/apache/jasper/compiler/SmapUtil.java
Normal file
713
java/org/apache/jasper/compiler/SmapUtil.java
Normal file
File diff suppressed because it is too large
Load Diff
116
java/org/apache/jasper/compiler/TagConstants.java
Normal file
116
java/org/apache/jasper/compiler/TagConstants.java
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public interface TagConstants {
|
||||
|
||||
public static final String JSP_URI = "http://java.sun.com/JSP/Page";
|
||||
|
||||
public static final String DIRECTIVE_ACTION = "directive.";
|
||||
|
||||
public static final String ROOT_ACTION = "root";
|
||||
public static final String JSP_ROOT_ACTION = "jsp:root";
|
||||
|
||||
public static final String PAGE_DIRECTIVE_ACTION = "directive.page";
|
||||
public static final String JSP_PAGE_DIRECTIVE_ACTION = "jsp:directive.page";
|
||||
|
||||
public static final String INCLUDE_DIRECTIVE_ACTION = "directive.include";
|
||||
public static final String JSP_INCLUDE_DIRECTIVE_ACTION = "jsp:directive.include";
|
||||
|
||||
public static final String DECLARATION_ACTION = "declaration";
|
||||
public static final String JSP_DECLARATION_ACTION = "jsp:declaration";
|
||||
|
||||
public static final String SCRIPTLET_ACTION = "scriptlet";
|
||||
public static final String JSP_SCRIPTLET_ACTION = "jsp:scriptlet";
|
||||
|
||||
public static final String EXPRESSION_ACTION = "expression";
|
||||
public static final String JSP_EXPRESSION_ACTION = "jsp:expression";
|
||||
|
||||
public static final String USE_BEAN_ACTION = "useBean";
|
||||
public static final String JSP_USE_BEAN_ACTION = "jsp:useBean";
|
||||
|
||||
public static final String SET_PROPERTY_ACTION = "setProperty";
|
||||
public static final String JSP_SET_PROPERTY_ACTION = "jsp:setProperty";
|
||||
|
||||
public static final String GET_PROPERTY_ACTION = "getProperty";
|
||||
public static final String JSP_GET_PROPERTY_ACTION = "jsp:getProperty";
|
||||
|
||||
public static final String INCLUDE_ACTION = "include";
|
||||
public static final String JSP_INCLUDE_ACTION = "jsp:include";
|
||||
|
||||
public static final String FORWARD_ACTION = "forward";
|
||||
public static final String JSP_FORWARD_ACTION = "jsp:forward";
|
||||
|
||||
public static final String PARAM_ACTION = "param";
|
||||
public static final String JSP_PARAM_ACTION = "jsp:param";
|
||||
|
||||
public static final String PARAMS_ACTION = "params";
|
||||
public static final String JSP_PARAMS_ACTION = "jsp:params";
|
||||
|
||||
public static final String PLUGIN_ACTION = "plugin";
|
||||
public static final String JSP_PLUGIN_ACTION = "jsp:plugin";
|
||||
|
||||
public static final String FALLBACK_ACTION = "fallback";
|
||||
public static final String JSP_FALLBACK_ACTION = "jsp:fallback";
|
||||
|
||||
public static final String TEXT_ACTION = "text";
|
||||
public static final String JSP_TEXT_ACTION = "jsp:text";
|
||||
public static final String JSP_TEXT_ACTION_END = "</jsp:text>";
|
||||
|
||||
public static final String ATTRIBUTE_ACTION = "attribute";
|
||||
public static final String JSP_ATTRIBUTE_ACTION = "jsp:attribute";
|
||||
|
||||
public static final String BODY_ACTION = "body";
|
||||
public static final String JSP_BODY_ACTION = "jsp:body";
|
||||
|
||||
public static final String ELEMENT_ACTION = "element";
|
||||
public static final String JSP_ELEMENT_ACTION = "jsp:element";
|
||||
|
||||
public static final String OUTPUT_ACTION = "output";
|
||||
public static final String JSP_OUTPUT_ACTION = "jsp:output";
|
||||
|
||||
public static final String TAGLIB_DIRECTIVE_ACTION = "taglib";
|
||||
public static final String JSP_TAGLIB_DIRECTIVE_ACTION = "jsp:taglib";
|
||||
|
||||
/*
|
||||
* Tag Files
|
||||
*/
|
||||
public static final String INVOKE_ACTION = "invoke";
|
||||
public static final String JSP_INVOKE_ACTION = "jsp:invoke";
|
||||
|
||||
public static final String DOBODY_ACTION = "doBody";
|
||||
public static final String JSP_DOBODY_ACTION = "jsp:doBody";
|
||||
|
||||
/*
|
||||
* Tag File Directives
|
||||
*/
|
||||
public static final String TAG_DIRECTIVE_ACTION = "directive.tag";
|
||||
public static final String JSP_TAG_DIRECTIVE_ACTION = "jsp:directive.tag";
|
||||
|
||||
public static final String ATTRIBUTE_DIRECTIVE_ACTION = "directive.attribute";
|
||||
public static final String JSP_ATTRIBUTE_DIRECTIVE_ACTION = "jsp:directive.attribute";
|
||||
|
||||
public static final String VARIABLE_DIRECTIVE_ACTION = "directive.variable";
|
||||
public static final String JSP_VARIABLE_DIRECTIVE_ACTION = "jsp:directive.variable";
|
||||
|
||||
/*
|
||||
* Directive attributes
|
||||
*/
|
||||
public static final String URN_JSPTAGDIR = "urn:jsptagdir:";
|
||||
public static final String URN_JSPTLD = "urn:jsptld:";
|
||||
}
|
||||
712
java/org/apache/jasper/compiler/TagFileProcessor.java
Normal file
712
java/org/apache/jasper/compiler/TagFileProcessor.java
Normal file
File diff suppressed because it is too large
Load Diff
393
java/org/apache/jasper/compiler/TagLibraryInfoImpl.java
Normal file
393
java/org/apache/jasper/compiler/TagLibraryInfoImpl.java
Normal file
@@ -0,0 +1,393 @@
|
||||
/*
|
||||
* 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.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.jsp.tagext.FunctionInfo;
|
||||
import javax.servlet.jsp.tagext.PageData;
|
||||
import javax.servlet.jsp.tagext.TagAttributeInfo;
|
||||
import javax.servlet.jsp.tagext.TagExtraInfo;
|
||||
import javax.servlet.jsp.tagext.TagFileInfo;
|
||||
import javax.servlet.jsp.tagext.TagInfo;
|
||||
import javax.servlet.jsp.tagext.TagLibraryInfo;
|
||||
import javax.servlet.jsp.tagext.TagLibraryValidator;
|
||||
import javax.servlet.jsp.tagext.TagVariableInfo;
|
||||
import javax.servlet.jsp.tagext.ValidationMessage;
|
||||
|
||||
import org.apache.jasper.JasperException;
|
||||
import org.apache.jasper.JspCompilationContext;
|
||||
import org.apache.tomcat.Jar;
|
||||
import org.apache.tomcat.util.descriptor.tld.TagFileXml;
|
||||
import org.apache.tomcat.util.descriptor.tld.TagXml;
|
||||
import org.apache.tomcat.util.descriptor.tld.TaglibXml;
|
||||
import org.apache.tomcat.util.descriptor.tld.TldResourcePath;
|
||||
import org.apache.tomcat.util.descriptor.tld.ValidatorXml;
|
||||
|
||||
/**
|
||||
* Implementation of the TagLibraryInfo class from the JSP spec.
|
||||
*
|
||||
* @author Anil K. Vijendran
|
||||
* @author Mandar Raje
|
||||
* @author Pierre Delisle
|
||||
* @author Kin-man Chung
|
||||
* @author Jan Luehe
|
||||
*/
|
||||
class TagLibraryInfoImpl extends TagLibraryInfo implements TagConstants {
|
||||
|
||||
private final JspCompilationContext ctxt;
|
||||
|
||||
private final PageInfo pi;
|
||||
|
||||
private final ErrorDispatcher err;
|
||||
|
||||
private final ParserController parserController;
|
||||
|
||||
private static void print(String name, String value, PrintWriter w) {
|
||||
if (value != null) {
|
||||
w.print(name + " = {\n\t");
|
||||
w.print(value);
|
||||
w.print("\n}\n");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter out = new PrintWriter(sw);
|
||||
print("tlibversion", tlibversion, out);
|
||||
print("jspversion", jspversion, out);
|
||||
print("shortname", shortname, out);
|
||||
print("urn", urn, out);
|
||||
print("info", info, out);
|
||||
print("uri", uri, out);
|
||||
print("tagLibraryValidator", "" + tagLibraryValidator, out);
|
||||
|
||||
for (TagInfo tag : tags) {
|
||||
out.println(tag.toString());
|
||||
}
|
||||
|
||||
for (TagFileInfo tagFile : tagFiles) {
|
||||
out.println(tagFile.toString());
|
||||
}
|
||||
|
||||
for (FunctionInfo function : functions) {
|
||||
out.println(function.toString());
|
||||
}
|
||||
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
|
||||
public TagLibraryInfoImpl(JspCompilationContext ctxt, ParserController pc,
|
||||
PageInfo pi, String prefix, String uriIn,
|
||||
TldResourcePath tldResourcePath, ErrorDispatcher err)
|
||||
throws JasperException {
|
||||
super(prefix, uriIn);
|
||||
|
||||
this.ctxt = ctxt;
|
||||
this.parserController = pc;
|
||||
this.pi = pi;
|
||||
this.err = err;
|
||||
|
||||
if (tldResourcePath == null) {
|
||||
// The URI points to the TLD itself or to a JAR file in which the TLD is stored
|
||||
tldResourcePath = generateTldResourcePath(uri, ctxt);
|
||||
}
|
||||
|
||||
try (Jar jar = tldResourcePath.openJar()) {
|
||||
|
||||
// Add the dependencies on the TLD to the referencing page
|
||||
PageInfo pageInfo = ctxt.createCompiler().getPageInfo();
|
||||
if (pageInfo != null) {
|
||||
// If the TLD is in a JAR, that JAR may not be part of the web
|
||||
// application
|
||||
String path = tldResourcePath.getWebappPath();
|
||||
if (path != null) {
|
||||
// Add TLD (jar==null) / JAR (jar!=null) file to dependency list
|
||||
// 2nd parameter is null since the path is always relative
|
||||
// to the root of the web application even if we are
|
||||
// processing a reference from a tag packaged in a JAR.
|
||||
pageInfo.addDependant(path, ctxt.getLastModified(path, null));
|
||||
}
|
||||
if (jar != null) {
|
||||
if (path == null) {
|
||||
// JAR not in the web application so add it directly
|
||||
URL jarUrl = jar.getJarFileURL();
|
||||
long lastMod = -1;
|
||||
URLConnection urlConn = null;
|
||||
try {
|
||||
urlConn = jarUrl.openConnection();
|
||||
lastMod = urlConn.getLastModified();
|
||||
} catch (IOException ioe) {
|
||||
throw new JasperException(ioe);
|
||||
} finally {
|
||||
if (urlConn != null) {
|
||||
try {
|
||||
urlConn.getInputStream().close();
|
||||
} catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
pageInfo.addDependant(jarUrl.toExternalForm(),
|
||||
Long.valueOf(lastMod));
|
||||
}
|
||||
// Add TLD within the JAR to the dependency list
|
||||
String entryName = tldResourcePath.getEntryName();
|
||||
try {
|
||||
pageInfo.addDependant(jar.getURL(entryName),
|
||||
Long.valueOf(jar.getLastModified(entryName)));
|
||||
} catch (IOException ioe) {
|
||||
throw new JasperException(ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the representation of the TLD
|
||||
if (tldResourcePath.getUrl() == null) {
|
||||
err.jspError("jsp.error.tld.missing", prefix, uri);
|
||||
}
|
||||
TaglibXml taglibXml =
|
||||
ctxt.getOptions().getTldCache().getTaglibXml(tldResourcePath);
|
||||
if (taglibXml == null) {
|
||||
err.jspError("jsp.error.tld.missing", prefix, uri);
|
||||
}
|
||||
|
||||
// Populate the TagLibraryInfo attributes
|
||||
// Never null. jspError always throws an Exception
|
||||
// Slightly convoluted so the @SuppressWarnings has minimal scope
|
||||
@SuppressWarnings("null")
|
||||
String v = taglibXml.getJspVersion();
|
||||
this.jspversion = v;
|
||||
this.tlibversion = taglibXml.getTlibVersion();
|
||||
this.shortname = taglibXml.getShortName();
|
||||
this.urn = taglibXml.getUri();
|
||||
this.info = taglibXml.getInfo();
|
||||
|
||||
this.tagLibraryValidator = createValidator(taglibXml.getValidator());
|
||||
|
||||
List<TagInfo> tagInfos = new ArrayList<>();
|
||||
for (TagXml tagXml : taglibXml.getTags()) {
|
||||
tagInfos.add(createTagInfo(tagXml));
|
||||
}
|
||||
|
||||
List<TagFileInfo> tagFileInfos = new ArrayList<>();
|
||||
for (TagFileXml tagFileXml : taglibXml.getTagFiles()) {
|
||||
tagFileInfos.add(createTagFileInfo(tagFileXml, jar));
|
||||
}
|
||||
|
||||
Set<String> names = new HashSet<>();
|
||||
List<FunctionInfo> functionInfos = taglibXml.getFunctions();
|
||||
// TODO Move this validation to the parsing stage
|
||||
for (FunctionInfo functionInfo : functionInfos) {
|
||||
String name = functionInfo.getName();
|
||||
if (!names.add(name)) {
|
||||
err.jspError("jsp.error.tld.fn.duplicate.name", name, uri);
|
||||
}
|
||||
}
|
||||
|
||||
if (tlibversion == null) {
|
||||
err.jspError("jsp.error.tld.mandatory.element.missing", "tlib-version", uri);
|
||||
}
|
||||
if (jspversion == null) {
|
||||
err.jspError("jsp.error.tld.mandatory.element.missing", "jsp-version", uri);
|
||||
}
|
||||
|
||||
this.tags = tagInfos.toArray(new TagInfo[tagInfos.size()]);
|
||||
this.tagFiles = tagFileInfos.toArray(new TagFileInfo[tagFileInfos.size()]);
|
||||
this.functions = functionInfos.toArray(new FunctionInfo[functionInfos.size()]);
|
||||
} catch (IOException ioe) {
|
||||
throw new JasperException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagLibraryInfo[] getTagLibraryInfos() {
|
||||
Collection<TagLibraryInfo> coll = pi.getTaglibs();
|
||||
return coll.toArray(new TagLibraryInfo[coll.size()]);
|
||||
}
|
||||
|
||||
/*
|
||||
* @param uri The uri of the TLD
|
||||
* @param ctxt The compilation context
|
||||
*
|
||||
* @return the location of the TLD identified by the uri
|
||||
*/
|
||||
private TldResourcePath generateTldResourcePath(String uri,
|
||||
JspCompilationContext ctxt) throws JasperException {
|
||||
|
||||
// TODO: this matches the current implementation but the URL logic looks fishy
|
||||
// map URI to location per JSP 7.3.6.2
|
||||
if (uri.indexOf(':') != -1) {
|
||||
// abs_uri, this was not found in the taglibMap so raise an error
|
||||
err.jspError("jsp.error.taglibDirective.absUriCannotBeResolved", uri);
|
||||
} else if (uri.charAt(0) != '/') {
|
||||
// noroot_rel_uri, resolve against the current JSP page
|
||||
uri = ctxt.resolveRelativeUri(uri);
|
||||
try {
|
||||
// Can't use RequestUtils.normalize since that package is not
|
||||
// available to Jasper.
|
||||
uri = (new URI(uri)).normalize().toString();
|
||||
if (uri.startsWith("../")) {
|
||||
// Trying to go outside context root
|
||||
err.jspError("jsp.error.taglibDirective.uriInvalid", uri);
|
||||
}
|
||||
} catch (URISyntaxException e) {
|
||||
err.jspError("jsp.error.taglibDirective.uriInvalid", uri);
|
||||
}
|
||||
}
|
||||
|
||||
URL url = null;
|
||||
try {
|
||||
url = ctxt.getResource(uri);
|
||||
} catch (Exception ex) {
|
||||
err.jspError("jsp.error.tld.unable_to_get_jar", uri, ex.toString());
|
||||
}
|
||||
if (uri.endsWith(".jar")) {
|
||||
if (url == null) {
|
||||
err.jspError("jsp.error.tld.missing_jar", uri);
|
||||
}
|
||||
return new TldResourcePath(url, uri, "META-INF/taglib.tld");
|
||||
} else if (uri.startsWith("/WEB-INF/lib/") || uri.startsWith("/WEB-INF/classes/") ||
|
||||
(uri.startsWith("/WEB-INF/tags/") && uri.endsWith(".tld")&& !uri.endsWith("implicit.tld"))) {
|
||||
err.jspError("jsp.error.tld.invalid_tld_file", uri);
|
||||
}
|
||||
return new TldResourcePath(url, uri);
|
||||
}
|
||||
|
||||
private TagInfo createTagInfo(TagXml tagXml) throws JasperException {
|
||||
|
||||
String teiClassName = tagXml.getTeiClass();
|
||||
TagExtraInfo tei = null;
|
||||
if (teiClassName != null && !teiClassName.isEmpty()) {
|
||||
try {
|
||||
Class<?> teiClass = ctxt.getClassLoader().loadClass(teiClassName);
|
||||
tei = (TagExtraInfo) teiClass.getConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
err.jspError(e, "jsp.error.teiclass.instantiation", teiClassName);
|
||||
}
|
||||
}
|
||||
|
||||
List<TagAttributeInfo> attributeInfos = tagXml.getAttributes();
|
||||
List<TagVariableInfo> variableInfos = tagXml.getVariables();
|
||||
|
||||
return new TagInfo(tagXml.getName(),
|
||||
tagXml.getTagClass(),
|
||||
tagXml.getBodyContent(),
|
||||
tagXml.getInfo(),
|
||||
this,
|
||||
tei,
|
||||
attributeInfos.toArray(new TagAttributeInfo[attributeInfos.size()]),
|
||||
tagXml.getDisplayName(),
|
||||
tagXml.getSmallIcon(),
|
||||
tagXml.getLargeIcon(),
|
||||
variableInfos.toArray(new TagVariableInfo[variableInfos.size()]),
|
||||
tagXml.hasDynamicAttributes());
|
||||
}
|
||||
|
||||
private TagFileInfo createTagFileInfo(TagFileXml tagFileXml, Jar jar) throws JasperException {
|
||||
|
||||
String name = tagFileXml.getName();
|
||||
String path = tagFileXml.getPath();
|
||||
|
||||
if (path == null) {
|
||||
// path is required
|
||||
err.jspError("jsp.error.tagfile.missingPath");
|
||||
} else if (!path.startsWith("/META-INF/tags") && !path.startsWith("/WEB-INF/tags")) {
|
||||
err.jspError("jsp.error.tagfile.illegalPath", path);
|
||||
}
|
||||
|
||||
TagInfo tagInfo =
|
||||
TagFileProcessor.parseTagFileDirectives(parserController, name, path, jar, this);
|
||||
return new TagFileInfo(name, path, tagInfo);
|
||||
}
|
||||
|
||||
private TagLibraryValidator createValidator(ValidatorXml validatorXml) throws JasperException {
|
||||
|
||||
if (validatorXml == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String validatorClass = validatorXml.getValidatorClass();
|
||||
if (validatorClass == null || validatorClass.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String,Object> initParams = new Hashtable<>();
|
||||
initParams.putAll(validatorXml.getInitParams());
|
||||
|
||||
try {
|
||||
Class<?> tlvClass = ctxt.getClassLoader().loadClass(validatorClass);
|
||||
TagLibraryValidator tlv = (TagLibraryValidator) tlvClass.getConstructor().newInstance();
|
||||
tlv.setInitParameters(initParams);
|
||||
return tlv;
|
||||
} catch (Exception e) {
|
||||
err.jspError(e, "jsp.error.tlvclass.instantiation", validatorClass);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// *********************************************************************
|
||||
// Until javax.servlet.jsp.tagext.TagLibraryInfo is fixed
|
||||
|
||||
/**
|
||||
* The instance (if any) for the TagLibraryValidator class.
|
||||
*
|
||||
* @return The TagLibraryValidator instance, if any.
|
||||
*/
|
||||
public TagLibraryValidator getTagLibraryValidator() {
|
||||
return tagLibraryValidator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translation-time validation of the XML document associated with the JSP
|
||||
* page. This is a convenience method on the associated TagLibraryValidator
|
||||
* class.
|
||||
*
|
||||
* @param thePage
|
||||
* The JSP page object
|
||||
* @return A string indicating whether the page is valid or not.
|
||||
*/
|
||||
public ValidationMessage[] validate(PageData thePage) {
|
||||
TagLibraryValidator tlv = getTagLibraryValidator();
|
||||
if (tlv == null)
|
||||
return null;
|
||||
|
||||
String uri = getURI();
|
||||
if (uri.startsWith("/")) {
|
||||
uri = URN_JSPTLD + uri;
|
||||
}
|
||||
|
||||
return tlv.validate(getPrefixString(), uri, thePage);
|
||||
}
|
||||
|
||||
private TagLibraryValidator tagLibraryValidator;
|
||||
}
|
||||
291
java/org/apache/jasper/compiler/TagPluginManager.java
Normal file
291
java/org/apache/jasper/compiler/TagPluginManager.java
Normal file
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* 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.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.security.AccessController;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.apache.jasper.Constants;
|
||||
import org.apache.jasper.JasperException;
|
||||
import org.apache.jasper.compiler.tagplugin.TagPlugin;
|
||||
import org.apache.jasper.compiler.tagplugin.TagPluginContext;
|
||||
import org.apache.tomcat.util.descriptor.tagplugin.TagPluginParser;
|
||||
import org.apache.tomcat.util.security.PrivilegedGetTccl;
|
||||
import org.apache.tomcat.util.security.PrivilegedSetTccl;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Manages tag plugin optimizations.
|
||||
*
|
||||
* @author Kin-man Chung
|
||||
*/
|
||||
public class TagPluginManager {
|
||||
|
||||
private static final String META_INF_JASPER_TAG_PLUGINS_XML =
|
||||
"META-INF/org.apache.jasper/tagPlugins.xml";
|
||||
private static final String TAG_PLUGINS_XML = "/WEB-INF/tagPlugins.xml";
|
||||
private final ServletContext ctxt;
|
||||
private HashMap<String, TagPlugin> tagPlugins;
|
||||
private boolean initialized = false;
|
||||
|
||||
public TagPluginManager(ServletContext ctxt) {
|
||||
this.ctxt = ctxt;
|
||||
}
|
||||
|
||||
public void apply(Node.Nodes page, ErrorDispatcher err, PageInfo pageInfo)
|
||||
throws JasperException {
|
||||
|
||||
init(err);
|
||||
if (!tagPlugins.isEmpty()) {
|
||||
page.visit(new NodeVisitor(this, pageInfo));
|
||||
}
|
||||
}
|
||||
|
||||
private void init(ErrorDispatcher err) throws JasperException {
|
||||
if (initialized)
|
||||
return;
|
||||
|
||||
String blockExternalString = ctxt.getInitParameter(
|
||||
Constants.XML_BLOCK_EXTERNAL_INIT_PARAM);
|
||||
boolean blockExternal;
|
||||
if (blockExternalString == null) {
|
||||
blockExternal = true;
|
||||
} else {
|
||||
blockExternal = Boolean.parseBoolean(blockExternalString);
|
||||
}
|
||||
|
||||
TagPluginParser parser;
|
||||
ClassLoader original;
|
||||
if (Constants.IS_SECURITY_ENABLED) {
|
||||
PrivilegedGetTccl pa = new PrivilegedGetTccl();
|
||||
original = AccessController.doPrivileged(pa);
|
||||
} else {
|
||||
original = Thread.currentThread().getContextClassLoader();
|
||||
}
|
||||
try {
|
||||
if (Constants.IS_SECURITY_ENABLED) {
|
||||
PrivilegedSetTccl pa =
|
||||
new PrivilegedSetTccl(TagPluginManager.class.getClassLoader());
|
||||
AccessController.doPrivileged(pa);
|
||||
} else {
|
||||
Thread.currentThread().setContextClassLoader(
|
||||
TagPluginManager.class.getClassLoader());
|
||||
}
|
||||
|
||||
parser = new TagPluginParser(ctxt, blockExternal);
|
||||
|
||||
Enumeration<URL> urls =
|
||||
ctxt.getClassLoader().getResources(META_INF_JASPER_TAG_PLUGINS_XML);
|
||||
while (urls.hasMoreElements()) {
|
||||
URL url = urls.nextElement();
|
||||
parser.parse(url);
|
||||
}
|
||||
|
||||
URL url = ctxt.getResource(TAG_PLUGINS_XML);
|
||||
if (url != null) {
|
||||
parser.parse(url);
|
||||
}
|
||||
} catch (IOException | SAXException e) {
|
||||
throw new JasperException(e);
|
||||
} finally {
|
||||
if (Constants.IS_SECURITY_ENABLED) {
|
||||
PrivilegedSetTccl pa = new PrivilegedSetTccl(original);
|
||||
AccessController.doPrivileged(pa);
|
||||
} else {
|
||||
Thread.currentThread().setContextClassLoader(original);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String> plugins = parser.getPlugins();
|
||||
tagPlugins = new HashMap<>(plugins.size());
|
||||
for (Map.Entry<String, String> entry : plugins.entrySet()) {
|
||||
try {
|
||||
String tagClass = entry.getKey();
|
||||
String pluginName = entry.getValue();
|
||||
Class<?> pluginClass = ctxt.getClassLoader().loadClass(pluginName);
|
||||
TagPlugin plugin = (TagPlugin) pluginClass.getConstructor().newInstance();
|
||||
tagPlugins.put(tagClass, plugin);
|
||||
} catch (Exception e) {
|
||||
err.jspError(e);
|
||||
}
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke tag plugin for the given custom tag, if a plugin exists for
|
||||
* the custom tag's tag handler.
|
||||
* <p/>
|
||||
* The given custom tag node will be manipulated by the plugin.
|
||||
*/
|
||||
private void invokePlugin(Node.CustomTag n, PageInfo pageInfo) {
|
||||
TagPlugin tagPlugin = tagPlugins.get(n.getTagHandlerClass().getName());
|
||||
if (tagPlugin == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
TagPluginContext tagPluginContext = new TagPluginContextImpl(n, pageInfo);
|
||||
n.setTagPluginContext(tagPluginContext);
|
||||
tagPlugin.doTag(tagPluginContext);
|
||||
}
|
||||
|
||||
private static class NodeVisitor extends Node.Visitor {
|
||||
private final TagPluginManager manager;
|
||||
private final PageInfo pageInfo;
|
||||
|
||||
public NodeVisitor(TagPluginManager manager, PageInfo pageInfo) {
|
||||
this.manager = manager;
|
||||
this.pageInfo = pageInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.CustomTag n) throws JasperException {
|
||||
manager.invokePlugin(n, pageInfo);
|
||||
visitBody(n);
|
||||
}
|
||||
}
|
||||
|
||||
private static class TagPluginContextImpl implements TagPluginContext {
|
||||
private final Node.CustomTag node;
|
||||
private final PageInfo pageInfo;
|
||||
private final HashMap<String, Object> pluginAttributes;
|
||||
private Node.Nodes curNodes;
|
||||
|
||||
TagPluginContextImpl(Node.CustomTag n, PageInfo pageInfo) {
|
||||
this.node = n;
|
||||
this.pageInfo = pageInfo;
|
||||
curNodes = new Node.Nodes();
|
||||
n.setAtETag(curNodes);
|
||||
curNodes = new Node.Nodes();
|
||||
n.setAtSTag(curNodes);
|
||||
n.setUseTagPlugin(true);
|
||||
pluginAttributes = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagPluginContext getParentContext() {
|
||||
Node parent = node.getParent();
|
||||
if (!(parent instanceof Node.CustomTag)) {
|
||||
return null;
|
||||
}
|
||||
return ((Node.CustomTag) parent).getTagPluginContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPluginAttribute(String key, Object value) {
|
||||
pluginAttributes.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPluginAttribute(String key) {
|
||||
return pluginAttributes.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isScriptless() {
|
||||
return node.getChildInfo().isScriptless();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstantAttribute(String attribute) {
|
||||
Node.JspAttribute attr = getNodeAttribute(attribute);
|
||||
if (attr == null)
|
||||
return false;
|
||||
return attr.isLiteral();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConstantAttribute(String attribute) {
|
||||
Node.JspAttribute attr = getNodeAttribute(attribute);
|
||||
if (attr == null)
|
||||
return null;
|
||||
return attr.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAttributeSpecified(String attribute) {
|
||||
return getNodeAttribute(attribute) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemporaryVariableName() {
|
||||
return node.getRoot().nextTemporaryVariableName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateImport(String imp) {
|
||||
pageInfo.addImport(imp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateDeclaration(String id, String text) {
|
||||
if (pageInfo.isPluginDeclared(id)) {
|
||||
return;
|
||||
}
|
||||
curNodes.add(new Node.Declaration(text, node.getStart(), null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateJavaSource(String sourceCode) {
|
||||
curNodes.add(new Node.Scriptlet(sourceCode, node.getStart(),
|
||||
null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateAttribute(String attributeName) {
|
||||
curNodes.add(new Node.AttributeGenerator(node.getStart(),
|
||||
attributeName,
|
||||
node));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dontUseTagPlugin() {
|
||||
node.setUseTagPlugin(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateBody() {
|
||||
// Since we'll generate the body anyway, this is really a nop,
|
||||
// except for the fact that it lets us put the Java sources the
|
||||
// plugins produce in the correct order (w.r.t the body).
|
||||
curNodes = node.getAtETag();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTagFile() {
|
||||
return pageInfo.isTagFile();
|
||||
}
|
||||
|
||||
private Node.JspAttribute getNodeAttribute(String attribute) {
|
||||
Node.JspAttribute[] attrs = node.getJspAttributes();
|
||||
for (int i = 0; attrs != null && i < attrs.length; i++) {
|
||||
if (attrs[i].getName().equals(attribute)) {
|
||||
return attrs[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
124
java/org/apache/jasper/compiler/TextOptimizer.java
Normal file
124
java/org/apache/jasper/compiler/TextOptimizer.java
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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 org.apache.jasper.JasperException;
|
||||
import org.apache.jasper.Options;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class TextOptimizer {
|
||||
|
||||
/**
|
||||
* A visitor to concatenate contiguous template texts.
|
||||
*/
|
||||
private static class TextCatVisitor extends Node.Visitor {
|
||||
|
||||
private static final String EMPTY_TEXT = "";
|
||||
|
||||
private final Options options;
|
||||
private final PageInfo pageInfo;
|
||||
private int textNodeCount = 0;
|
||||
private Node.TemplateText firstTextNode = null;
|
||||
private StringBuilder textBuffer;
|
||||
|
||||
public TextCatVisitor(Compiler compiler) {
|
||||
options = compiler.getCompilationContext().getOptions();
|
||||
pageInfo = compiler.getPageInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doVisit(Node n) throws JasperException {
|
||||
collectText();
|
||||
}
|
||||
|
||||
/*
|
||||
* The following directives are ignored in text concatenation
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void visit(Node.PageDirective n) throws JasperException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.TagDirective n) throws JasperException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.TaglibDirective n) throws JasperException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.AttributeDirective n) throws JasperException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.VariableDirective n) throws JasperException {
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't concatenate text across body boundaries
|
||||
*/
|
||||
@Override
|
||||
public void visitBody(Node n) throws JasperException {
|
||||
super.visitBody(n);
|
||||
collectText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Node.TemplateText n) throws JasperException {
|
||||
if ((options.getTrimSpaces() || pageInfo.isTrimDirectiveWhitespaces())
|
||||
&& n.isAllSpace()) {
|
||||
n.setText(EMPTY_TEXT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (textNodeCount++ == 0) {
|
||||
firstTextNode = n;
|
||||
textBuffer = new StringBuilder(n.getText());
|
||||
} else {
|
||||
// Append text to text buffer
|
||||
textBuffer.append(n.getText());
|
||||
n.setText(EMPTY_TEXT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method breaks concatenation mode. As a side effect it copies
|
||||
* the concatenated string to the first text node
|
||||
*/
|
||||
private void collectText() {
|
||||
|
||||
if (textNodeCount > 1) {
|
||||
// Copy the text in buffer into the first template text node.
|
||||
firstTextNode.setText(textBuffer.toString());
|
||||
}
|
||||
textNodeCount = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void concatenate(Compiler compiler, Node.Nodes page)
|
||||
throws JasperException {
|
||||
|
||||
TextCatVisitor v = new TextCatVisitor(compiler);
|
||||
page.visit(v);
|
||||
|
||||
// Cleanup, in case the page ends with a template text
|
||||
v.collectText();
|
||||
}
|
||||
}
|
||||
188
java/org/apache/jasper/compiler/TldCache.java
Normal file
188
java/org/apache/jasper/compiler/TldCache.java
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* 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.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.apache.jasper.Constants;
|
||||
import org.apache.jasper.JasperException;
|
||||
import org.apache.tomcat.Jar;
|
||||
import org.apache.tomcat.util.descriptor.tld.TaglibXml;
|
||||
import org.apache.tomcat.util.descriptor.tld.TldParser;
|
||||
import org.apache.tomcat.util.descriptor.tld.TldResourcePath;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* This class caches parsed instances of TLD files to remove the need for the
|
||||
* same TLD to be parsed for each JSP that references it. It does not protect
|
||||
* against multiple threads processing the same, new TLD but it does ensure that
|
||||
* each all threads will use the same TLD object after parsing.
|
||||
*/
|
||||
public class TldCache {
|
||||
|
||||
public static final String SERVLET_CONTEXT_ATTRIBUTE_NAME =
|
||||
TldCache.class.getName();
|
||||
|
||||
private final ServletContext servletContext;
|
||||
private final Map<String,TldResourcePath> uriTldResourcePathMap = new HashMap<>();
|
||||
private final Map<TldResourcePath,TaglibXmlCacheEntry> tldResourcePathTaglibXmlMap =
|
||||
new HashMap<>();
|
||||
private final TldParser tldParser;
|
||||
|
||||
|
||||
public static TldCache getInstance(ServletContext servletContext) {
|
||||
if (servletContext == null) {
|
||||
throw new IllegalArgumentException(Localizer.getMessage(
|
||||
"org.apache.jasper.compiler.TldCache.servletContextNull"));
|
||||
}
|
||||
return (TldCache) servletContext.getAttribute(SERVLET_CONTEXT_ATTRIBUTE_NAME);
|
||||
}
|
||||
|
||||
|
||||
public TldCache(ServletContext servletContext,
|
||||
Map<String, TldResourcePath> uriTldResourcePathMap,
|
||||
Map<TldResourcePath, TaglibXml> tldResourcePathTaglibXmlMap) {
|
||||
this.servletContext = servletContext;
|
||||
this.uriTldResourcePathMap.putAll(uriTldResourcePathMap);
|
||||
for (Entry<TldResourcePath, TaglibXml> entry : tldResourcePathTaglibXmlMap.entrySet()) {
|
||||
TldResourcePath tldResourcePath = entry.getKey();
|
||||
long lastModified[] = getLastModified(tldResourcePath);
|
||||
TaglibXmlCacheEntry cacheEntry = new TaglibXmlCacheEntry(
|
||||
entry.getValue(), lastModified[0], lastModified[1]);
|
||||
this.tldResourcePathTaglibXmlMap.put(tldResourcePath, cacheEntry);
|
||||
}
|
||||
boolean validate = Boolean.parseBoolean(
|
||||
servletContext.getInitParameter(Constants.XML_VALIDATION_TLD_INIT_PARAM));
|
||||
String blockExternalString = servletContext.getInitParameter(
|
||||
Constants.XML_BLOCK_EXTERNAL_INIT_PARAM);
|
||||
boolean blockExternal;
|
||||
if (blockExternalString == null) {
|
||||
blockExternal = true;
|
||||
} else {
|
||||
blockExternal = Boolean.parseBoolean(blockExternalString);
|
||||
}
|
||||
tldParser = new TldParser(true, validate, blockExternal);
|
||||
}
|
||||
|
||||
|
||||
public TldResourcePath getTldResourcePath(String uri) {
|
||||
return uriTldResourcePathMap.get(uri);
|
||||
}
|
||||
|
||||
|
||||
public TaglibXml getTaglibXml(TldResourcePath tldResourcePath) throws JasperException {
|
||||
TaglibXmlCacheEntry cacheEntry = tldResourcePathTaglibXmlMap.get(tldResourcePath);
|
||||
if (cacheEntry == null) {
|
||||
return null;
|
||||
}
|
||||
long lastModified[] = getLastModified(tldResourcePath);
|
||||
if (lastModified[0] != cacheEntry.getWebAppPathLastModified() ||
|
||||
lastModified[1] != cacheEntry.getEntryLastModified()) {
|
||||
synchronized (cacheEntry) {
|
||||
if (lastModified[0] != cacheEntry.getWebAppPathLastModified() ||
|
||||
lastModified[1] != cacheEntry.getEntryLastModified()) {
|
||||
// Re-parse TLD
|
||||
TaglibXml updatedTaglibXml;
|
||||
try {
|
||||
updatedTaglibXml = tldParser.parse(tldResourcePath);
|
||||
} catch (IOException | SAXException e) {
|
||||
throw new JasperException(e);
|
||||
}
|
||||
cacheEntry.setTaglibXml(updatedTaglibXml);
|
||||
cacheEntry.setWebAppPathLastModified(lastModified[0]);
|
||||
cacheEntry.setEntryLastModified(lastModified[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return cacheEntry.getTaglibXml();
|
||||
}
|
||||
|
||||
|
||||
private long[] getLastModified(TldResourcePath tldResourcePath) {
|
||||
long[] result = new long[2];
|
||||
result[0] = -1;
|
||||
result[1] = -1;
|
||||
try {
|
||||
String webappPath = tldResourcePath.getWebappPath();
|
||||
if (webappPath != null) {
|
||||
// webappPath will be null for JARs containing TLDs that are on
|
||||
// the class path but not part of the web application
|
||||
URL url = servletContext.getResource(tldResourcePath.getWebappPath());
|
||||
URLConnection conn = url.openConnection();
|
||||
result[0] = conn.getLastModified();
|
||||
if ("file".equals(url.getProtocol())) {
|
||||
// Reading the last modified time opens an input stream so we
|
||||
// need to make sure it is closed again otherwise the TLD file
|
||||
// will be locked until GC runs.
|
||||
conn.getInputStream().close();
|
||||
}
|
||||
}
|
||||
try (Jar jar = tldResourcePath.openJar()) {
|
||||
if (jar != null) {
|
||||
result[1] = jar.getLastModified(tldResourcePath.getEntryName());
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Ignore (shouldn't happen)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class TaglibXmlCacheEntry {
|
||||
private volatile TaglibXml taglibXml;
|
||||
private volatile long webAppPathLastModified;
|
||||
private volatile long entryLastModified;
|
||||
|
||||
public TaglibXmlCacheEntry(TaglibXml taglibXml, long webAppPathLastModified,
|
||||
long entryLastModified) {
|
||||
this.taglibXml = taglibXml;
|
||||
this.webAppPathLastModified = webAppPathLastModified;
|
||||
this.entryLastModified = entryLastModified;
|
||||
}
|
||||
|
||||
public TaglibXml getTaglibXml() {
|
||||
return taglibXml;
|
||||
}
|
||||
|
||||
public void setTaglibXml(TaglibXml taglibXml) {
|
||||
this.taglibXml = taglibXml;
|
||||
}
|
||||
|
||||
public long getWebAppPathLastModified() {
|
||||
return webAppPathLastModified;
|
||||
}
|
||||
|
||||
public void setWebAppPathLastModified(long webAppPathLastModified) {
|
||||
this.webAppPathLastModified = webAppPathLastModified;
|
||||
}
|
||||
|
||||
public long getEntryLastModified() {
|
||||
return entryLastModified;
|
||||
}
|
||||
|
||||
public void setEntryLastModified(long entryLastModified) {
|
||||
this.entryLastModified = entryLastModified;
|
||||
}
|
||||
}
|
||||
}
|
||||
1918
java/org/apache/jasper/compiler/Validator.java
Normal file
1918
java/org/apache/jasper/compiler/Validator.java
Normal file
File diff suppressed because it is too large
Load Diff
37
java/org/apache/jasper/compiler/tagplugin/TagPlugin.java
Normal file
37
java/org/apache/jasper/compiler/tagplugin/TagPlugin.java
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.tagplugin;
|
||||
|
||||
/**
|
||||
* This interface is to be implemented by the plugin author, to supply
|
||||
* an alternate implementation of the tag handlers. It can be used to
|
||||
* specify the Java codes to be generated when a tag is invoked.
|
||||
*
|
||||
* An implementation of this interface must be registered in a file
|
||||
* named "tagPlugins.xml" under WEB-INF.
|
||||
*/
|
||||
|
||||
public interface TagPlugin {
|
||||
|
||||
/**
|
||||
* Generate codes for a custom tag.
|
||||
* @param ctxt a TagPluginContext for accessing Jasper functions
|
||||
*/
|
||||
void doTag(TagPluginContext ctxt);
|
||||
}
|
||||
|
||||
137
java/org/apache/jasper/compiler/tagplugin/TagPluginContext.java
Normal file
137
java/org/apache/jasper/compiler/tagplugin/TagPluginContext.java
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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.tagplugin;
|
||||
|
||||
|
||||
/**
|
||||
* This interface allows the plugin author to make inquiries about the
|
||||
* properties of the current tag, and to use Jasper resources to generate
|
||||
* direct Java codes in place of tag handler invocations.
|
||||
*/
|
||||
|
||||
public interface TagPluginContext {
|
||||
/**
|
||||
* @return true if the body of the tag is scriptless.
|
||||
*/
|
||||
boolean isScriptless();
|
||||
|
||||
/**
|
||||
* @param attribute Name of the attribute
|
||||
* @return true if the attribute is specified in the tag
|
||||
*/
|
||||
boolean isAttributeSpecified(String attribute);
|
||||
|
||||
/**
|
||||
* @return A unique temporary variable name that the plugin can use.
|
||||
*/
|
||||
String getTemporaryVariableName();
|
||||
|
||||
/**
|
||||
* Generate an import statement
|
||||
* @param s Name of the import class, '*' allowed.
|
||||
*/
|
||||
void generateImport(String s);
|
||||
|
||||
/**
|
||||
* Generate a declaration in the of the generated class. This can be
|
||||
* used to declare an inner class, a method, or a class variable.
|
||||
* @param id A unique ID identifying the declaration. It is not
|
||||
* part of the declaration, and is used to ensure that the
|
||||
* declaration will only appear once. If this method is
|
||||
* invoked with the same id more than once in the translation
|
||||
* unit, only the first declaration will be taken.
|
||||
* @param text The text of the declaration.
|
||||
*/
|
||||
void generateDeclaration(String id, String text);
|
||||
|
||||
/**
|
||||
* Generate Java source code scriptlet
|
||||
* @param s the scriptlet (raw Java source)
|
||||
*/
|
||||
void generateJavaSource(String s);
|
||||
|
||||
/**
|
||||
* @param attribute The attribute name
|
||||
* @return true if the attribute is specified and its value is a
|
||||
* translation-time constant.
|
||||
*/
|
||||
boolean isConstantAttribute(String attribute);
|
||||
|
||||
/**
|
||||
* @param attribute The attribute name
|
||||
* @return A string that is the value of a constant attribute. Undefined
|
||||
* if the attribute is not a (translation-time) constant.
|
||||
* null if the attribute is not specified.
|
||||
*/
|
||||
String getConstantAttribute(String attribute);
|
||||
|
||||
/**
|
||||
* Generate codes to evaluate value of a attribute in the custom tag
|
||||
* The codes is a Java expression.
|
||||
* NOTE: Currently cannot handle attributes that are fragments.
|
||||
* @param attribute The specified attribute
|
||||
*/
|
||||
void generateAttribute(String attribute);
|
||||
|
||||
/**
|
||||
* Generate codes for the body of the custom tag
|
||||
*/
|
||||
void generateBody();
|
||||
|
||||
/**
|
||||
* Abandon optimization for this tag handler, and instruct
|
||||
* Jasper to generate the tag handler calls, as usual.
|
||||
* Should be invoked if errors are detected, or when the tag body
|
||||
* is deemed too complicated for optimization.
|
||||
*/
|
||||
void dontUseTagPlugin();
|
||||
|
||||
/**
|
||||
* Get the PluginContext for the parent of this custom tag. NOTE:
|
||||
* The operations available for PluginContext so obtained is limited
|
||||
* to getPluginAttribute and setPluginAttribute, and queries (e.g.
|
||||
* isScriptless(). There should be no calls to generate*().
|
||||
* @return The pluginContext for the parent node.
|
||||
* null if the parent is not a custom tag, or if the pluginContext
|
||||
* if not available (because useTagPlugin is false, e.g).
|
||||
*/
|
||||
TagPluginContext getParentContext();
|
||||
|
||||
/**
|
||||
* Associate the attribute with a value in the current tagplugin context.
|
||||
* The plugin attributes can be used for communication among tags that
|
||||
* must work together as a group. See <c:when> for an example.
|
||||
* @param attr The attribute name
|
||||
* @param value The attribute value
|
||||
*/
|
||||
void setPluginAttribute(String attr, Object value);
|
||||
|
||||
/**
|
||||
* Get the value of an attribute in the current tagplugin context.
|
||||
* @param attr The attribute name
|
||||
* @return the attribute value
|
||||
*/
|
||||
Object getPluginAttribute(String attr);
|
||||
|
||||
/**
|
||||
* Is the tag being used inside a tag file?
|
||||
* @return <code>true</code> if inside a tag file
|
||||
*/
|
||||
boolean isTagFile();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user