You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ki...@apache.org on 2003/03/19 21:51:35 UTC
cvs commit: jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/resources messages.properties jsp12.dtd
kinman 2003/03/19 12:51:35
Modified: jasper2/src/share/org/apache/jasper/compiler Compiler.java
Generator.java JspUtil.java Node.java PageInfo.java
Validator.java
jasper2/src/share/org/apache/jasper/resources
messages.properties
Added: jasper2/src/share/org/apache/jasper/compiler
ELFunctionMapper.java ELNode.java ELParser.java
Removed: jasper2/src/share/org/apache/jasper/compiler
FunctionMapperImpl.java
jasper2/src/share/org/apache/jasper/resources jsp12.dtd
Log:
- Remove FunctionMapperImpl.java since parseExpression does not validate
functions.
- Implement a EL expression parser. It only parses functions now, but
can be expanded to be a full parser, in the future.
- Modify Generator to output a function mapper for each invokation of
EL expression evaluation. The namespace for functions can now be reused,
if the page is in XML syntax.
Revision Changes Path
1.59 +4 -1 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Compiler.java
Index: Compiler.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Compiler.java,v
retrieving revision 1.58
retrieving revision 1.59
diff -u -r1.58 -r1.59
--- Compiler.java 27 Feb 2003 22:51:38 -0000 1.58
+++ Compiler.java 19 Mar 2003 20:51:34 -0000 1.59
@@ -253,7 +253,7 @@
// Generate FunctionMapper (used for validation of EL expressions and
// code generation)
- pageInfo.setFunctionMapper(new FunctionMapperImpl(this));
+ // pageInfo.setFunctionMapper(new FunctionMapperImpl(this));
// Validate and process attributes
Validator.validate(this, pageNodes);
@@ -278,6 +278,9 @@
// Optimizations by Tag Plugins
TagPluginManager tagPluginManager = options.getTagPluginManager();
tagPluginManager.apply(pageNodes, errDispatcher, pageInfo);
+
+ // Generate static funciton mapper codes.
+ ELFunctionMapper.map(this, pageNodes);
// generate servlet .java file
Generator.generate(writer, this, pageNodes);
1.174 +7 -74 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Generator.java
Index: Generator.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Generator.java,v
retrieving revision 1.173
retrieving revision 1.174
diff -u -r1.173 -r1.174
--- Generator.java 8 Mar 2003 00:58:09 -0000 1.173
+++ Generator.java 19 Mar 2003 20:51:34 -0000 1.174
@@ -435,10 +435,6 @@
out.printil("}");
out.println();
}
-
- // Static data for EL function and prefix maps:
- generateELFunctionMap();
- generateFunctionMapper();
}
/**
@@ -613,70 +609,6 @@
}
}
- /**
- * Generates EL Function map section
- */
- private void generateELFunctionMap()
- throws JasperException
- {
- FunctionMapperImpl fnMap = pageInfo.getFunctionMapper();
-
- out.printil("private static org.apache.jasper.runtime.ProtectedFunctionMapper _jspx_fnmap;");
- if (!fnMap.isEmpty()) {
- Iterator iter = fnMap.keySet().iterator();
- out.println();
- out.printil("static {");
- out.pushIndent();
- out.printil("_jspx_fnmap = org.apache.jasper.runtime.ProtectedFunctionMapper.getInstance();");
- while (iter.hasNext()) {
- String key = (String) iter.next();
- out.printin("_jspx_fnmap.mapFunction(");
- out.print(quote(key));
- out.print(", ");
- out.print(fnMap.getFunctionClass(key) + ".class, ");
- out.print(quote(fnMap.getMethodName(key)));
- out.print(", ");
- Class[] args = fnMap.getParameterTypes(key);
- if (args != null) {
- out.print("new Class[] {" );
- for( int j = 0; j < args.length; j++ ) {
- out.print( args[j].getName() + ".class" );
- if( j < (args.length - 1) ) {
- out.print( ", " );
- }
- }
- out.print("} ");
- } else {
- out.print("null");
- }
- out.println(");");
- }
- out.popIndent();
- out.printil("}");
- out.println();
- }
- }
-
- /**
- * Generates the method needed to implement FunctionMapper
- */
- private void generateFunctionMapper()
- throws JasperException
- {
-/* XX suppress until EL moves out of JSTL
- out.printil( "public java.lang.reflect.Method resolveFunction(" );
- out.printil( " String prefix, String localName )" );
- out.printil( "{" );
- out.pushIndent();
- out.printil( "return (java.lang.reflect.Method)_jspx_fnmap.get( " );
- out.printil( " prefix + \":\" + localName );" );
- out.popIndent();
- out.printil( "}" );
- out.println();
-*/
- }
-
-
/*
* Generates the constructor.
* (shared by servlet and tag handler preamble generation)
@@ -784,7 +716,7 @@
boolean replaceESC = v.indexOf(Constants.ESC) > 0;
v = JspUtil.interpreterCall(this.isTagFile,
v, expectedType, defaultPrefix,
- "_jspx_fnmap", false );
+ attr.getEL().getMapName(), false );
// XXX ESC replacement hack
if (replaceESC) {
v = "(" + v + ").replace(" + Constants.ESCStr + ", '$')";
@@ -867,7 +799,7 @@
"out.write("
+ JspUtil.interpreterCall(this.isTagFile,
"${" + new String(n.getText()) + "}", String.class,
- null, "_jspx_fnmap", false )
+ null, n.getEL().getMapName(), false )
+ ");");
} else {
out.printil("out.write(" +
@@ -2480,7 +2412,8 @@
// run attrValue through the expression interpreter
boolean replaceESC = attrValue.indexOf(Constants.ESC) > 0;
attrValue = JspUtil.interpreterCall(this.isTagFile,
- attrValue, c[0], n.getPrefix(), "_jspx_fnmap", false );
+ attrValue, c[0], n.getPrefix(),
+ attr.getEL().getMapName(), false );
// XXX hack: Replace ESC with '$'
if (replaceESC) {
attrValue = "(" + attrValue + ").replace(" +
1.34 +5 -10 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/JspUtil.java
Index: JspUtil.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/JspUtil.java,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -r1.33 -r1.34
--- JspUtil.java 26 Feb 2003 00:11:38 -0000 1.33
+++ JspUtil.java 19 Mar 2003 20:51:34 -0000 1.34
@@ -60,8 +60,6 @@
*/
package org.apache.jasper.compiler;
-import java.net.URL;
-
import java.io.*;
import java.util.Enumeration;
import java.util.Hashtable;
@@ -597,10 +595,10 @@
String defaultPrefix,
ErrorDispatcher err)
throws JasperException {
- // Just parse and check if any exceptions are thrown.
+
try {
JspUtil.expressionEvaluator.parseExpression( expressions,
- expectedType, functionMapper, defaultPrefix );
+ expectedType, null, defaultPrefix );
}
catch( ELParseException e ) {
err.jspError(where, "jsp.error.invalid.expression", expressions,
@@ -918,7 +916,4 @@
return reader;
}
}
-
-
-
1.66 +22 -8 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Node.java
Index: Node.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Node.java,v
retrieving revision 1.65
retrieving revision 1.66
diff -u -r1.65 -r1.66
--- Node.java 1 Mar 2003 02:07:52 -0000 1.65
+++ Node.java 19 Mar 2003 20:51:34 -0000 1.66
@@ -784,6 +784,8 @@
*/
public static class ELExpression extends Node {
+ private ELNode.Nodes el;
+
public ELExpression(String text, Mark start, Node parent) {
super(null, null, text, start, parent);
}
@@ -791,6 +793,14 @@
public void accept(Visitor v) throws JasperException {
v.visit(this);
}
+
+ public void setEL(ELNode.Nodes el) {
+ this.el = el;
+ }
+
+ public ELNode.Nodes getEL() {
+ return el;
+ }
}
/**
@@ -1766,8 +1776,8 @@
private String localName;
private String value;
private boolean expression;
- private boolean el;
private boolean dynamic;
+ private ELNode.Nodes el;
// If true, this JspAttribute represents a <jsp:attribute>
private boolean namedAttribute;
@@ -1775,7 +1785,7 @@
private NamedAttribute namedAttributeNode;
JspAttribute(String qName, String uri, String localName, String value,
- boolean expr, boolean el, boolean dyn ) {
+ boolean expr, ELNode.Nodes el, boolean dyn ) {
this.qName = qName;
this.uri = uri;
this.localName = localName;
@@ -1798,7 +1808,7 @@
this.value = null;
this.namedAttributeNode = na;
this.expression = false;
- this.el = false;
+ this.el = null;
this.dynamic = dyn;
this.namedAttribute = true;
}
@@ -1866,7 +1876,7 @@
* not be interpreted or reevaluated
*/
public boolean isELInterpreterInput() {
- return el;
+ return el != null;
}
/**
@@ -1874,7 +1884,7 @@
* time.
*/
public boolean isLiteral() {
- return !expression && !el && !namedAttribute;
+ return !expression && (el != null) && !namedAttribute;
}
/**
@@ -1882,6 +1892,10 @@
*/
public boolean isDynamic() {
return dynamic;
+ }
+
+ public ELNode.Nodes getEL() {
+ return el;
}
}
1.25 +3 -12 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/PageInfo.java
Index: PageInfo.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/PageInfo.java,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -r1.24 -r1.25
--- PageInfo.java 1 Mar 2003 02:07:52 -0000 1.24
+++ PageInfo.java 19 Mar 2003 20:51:35 -0000 1.25
@@ -78,7 +78,6 @@
private BeanRepository beanRepository;
private Hashtable tagLibraries;
private Hashtable prefixMapper;
- private FunctionMapperImpl funcMap;
private String language = "java";
private String xtends = Constants.JSP_SERVLET_BASE;
@@ -385,13 +384,5 @@
public void setOmitXmlDecl(String omit) {
omitXmlDecl = omit;
- }
-
- public void setFunctionMapper(FunctionMapperImpl map) {
- this.funcMap = map;
- }
-
- public FunctionMapperImpl getFunctionMapper() {
- return this.funcMap;
}
}
1.91 +89 -17 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Validator.java
Index: Validator.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Validator.java,v
retrieving revision 1.90
retrieving revision 1.91
diff -u -r1.90 -r1.91
--- Validator.java 4 Mar 2003 22:41:12 -0000 1.90
+++ Validator.java 19 Mar 2003 20:51:35 -0000 1.91
@@ -364,9 +364,6 @@
private ClassLoader loader;
private Hashtable taglibs;
- // A FunctionMapper, used to validate EL expressions.
- private FunctionMapper functionMapper;
-
private static final JspUtil.ValidAttribute[] jspRootAttrs = {
new JspUtil.ValidAttribute("version", true) };
@@ -448,7 +445,6 @@
this.err = compiler.getErrorDispatcher();
this.tagInfo = compiler.getCompilationContext().getTagInfo();
this.loader = compiler.getCompilationContext().getClassLoader();
- this.functionMapper = pageInfo.getFunctionMapper();
}
public void visit(Node.JspRoot n) throws JasperException {
@@ -653,15 +649,21 @@
}
public void visit(Node.ELExpression n) throws JasperException {
+ // Currently parseExpression does not validate functions, so
+ // a null FunctionMapper is passed.
if ( !pageInfo.isELIgnored() ) {
+ String expressions = "${" + new String(n.getText()) + "}";
JspUtil.validateExpressions(
n.getStart(),
- "${" + new String(n.getText()) + "}",
+ expressions,
java.lang.String.class, // XXX - Should template text
// always evaluate to String?
- this.functionMapper,
+ null,
null,
err);
+ ELNode.Nodes el = ELParser.parse(expressions);
+ validateFunctions(el, n);
+ n.setEL(el);
}
}
@@ -932,7 +934,7 @@
attrs.getLocalName(i),
attrs.getValue(i),
false,
- false,
+ null,
false);
}
if (jspAttrs[i].isExpression()) {
@@ -1058,7 +1060,7 @@
localName,
value.substring(2, value.length()-1),
true,
- false,
+ null,
dynamic);
}
else if(!n.isXmlSyntax() && value.startsWith("<%=")) {
@@ -1068,7 +1070,7 @@
localName,
value.substring(3, value.length()-2),
true,
- false,
+ null,
dynamic);
}
else {
@@ -1079,22 +1081,25 @@
// validate expression syntax if string contains
// expression(s)
- if (value.indexOf("${") != -1 && !pageInfo.isELIgnored()) {
+ ELNode.Nodes el = ELParser.parse(value);
+ if (el.containsEL() && !pageInfo.isELIgnored()) {
JspUtil.validateExpressions(
n.getStart(),
value,
expectedType,
- this.functionMapper,
+ null,
defaultPrefix,
this.err);
+
+ validateFunctions(el, n);
result = new Node.JspAttribute(qName, uri, localName,
- value, false, true,
+ value, false, el,
dynamic);
} else {
value = value.replace(Constants.ESC, '$');
result = new Node.JspAttribute(qName, uri, localName,
- value, false, false,
+ value, false, null,
dynamic);
}
}
@@ -1160,7 +1165,74 @@
return hasDynamicContent;
}
}
- }
+
+ private String findUri(String prefix, Node n) {
+
+ Node p = n;
+ while (p != null) {
+ if (p instanceof Node.CustomTag) {
+ Node.CustomTag ct = (Node.CustomTag) p;
+ if (prefix.equals(ct.getPrefix())) {
+ return (ct.getURI());
+ }
+ } else if (p instanceof Node.JspRoot) {
+ // XXX find Uri from the root node
+ }
+ p = p.getParent();
+ }
+ return null;
+ }
+
+ /**
+ * Validate functions in EL expressions
+ */
+ private void validateFunctions(ELNode.Nodes el, Node n)
+ throws JasperException {
+
+ class FVVisitor extends ELNode.Visitor {
+
+ Node n;
+
+ FVVisitor(Node n) {
+ this.n = n;
+ }
+
+ public void visit(ELNode.Function func) throws JasperException {
+ String defaultNS = null; // for now
+ String prefix = func.getPrefix();
+ String function = func.getName();
+ String uri = null;
+ if (prefix == null) {
+ // In XML syntax, use the default namespace
+ if (defaultNS == null) {
+ err.jspError(n, "jsp.error.noFuncionPrefix",
+ function);
+ }
+ uri = defaultNS;
+ } else if (n.isXmlSyntax()) {
+ uri = findUri(prefix, n);
+ } else {
+ Hashtable prefixMapper = pageInfo.getPrefixMapper();
+ uri = (String) prefixMapper.get(prefix);
+ }
+
+ TagLibraryInfo taglib =
+ (TagLibraryInfo) taglibs.get(uri);
+ FunctionInfo funcInfo = null;
+ if (taglib != null) {
+ funcInfo = taglib.getFunction(function);
+ }
+ if (funcInfo == null) {
+ err.jspError(n, "jsp.error.noFunction", function);
+ }
+ // Skip TLD function uniqueness check. Done by Schema ?
+ func.setFunctionInfo(funcInfo);
+ }
+ }
+
+ el.visit(new FVVisitor(n));
+ }
+ } // End of ValidateVisitor
/**
* A visitor for validating TagExtraInfo classes of all tags
1.1 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/ELFunctionMapper.java
Index: ELFunctionMapper.java
===================================================================
/* ========================================================================= *
* *
* The Apache Software License, Version 1.1 *
* *
* Copyright (c) 1999, 2000, 2001 The Apache Software Foundation. *
* All rights reserved. *
* *
* ========================================================================= *
* *
* Redistribution and use in source and binary forms, with or without modi- *
* fication, are permitted provided that the following conditions are met: *
* *
* 1. Redistributions of source code must retain the above copyright notice *
* notice, this list of conditions and the following disclaimer. *
* *
* 2. Redistributions in binary form must reproduce the above copyright *
* notice, this list of conditions and the following disclaimer in the *
* documentation and/or other materials provided with the distribution. *
* *
* 3. The end-user documentation included with the redistribution, if any, *
* must include the following acknowlegement: *
* *
* "This product includes software developed by the Apache Software *
* Foundation <http://www.apache.org/>." *
* *
* Alternately, this acknowlegement may appear in the software itself, if *
* and wherever such third-party acknowlegements normally appear. *
* *
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software *
* Foundation" must not be used to endorse or promote products derived *
* from this software without prior written permission. For written *
* permission, please contact <ap...@apache.org>. *
* *
* 5. Products derived from this software may not be called "Apache" nor may *
* "Apache" appear in their names without prior written permission of the *
* Apache Software Foundation. *
* *
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES *
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY *
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY *
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS *
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, *
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *
* POSSIBILITY OF SUCH DAMAGE. *
* *
* ========================================================================= *
* *
* This software consists of voluntary contributions made by many indivi- *
* duals on behalf of the Apache Software Foundation. For more information *
* on the Apache Software Foundation, please see <http://www.apache.org/>. *
* *
* ========================================================================= */
package org.apache.jasper.compiler;
import java.util.*;
import javax.servlet.jsp.tagext.FunctionInfo;
import org.apache.jasper.JasperException;
/**
* This class generates a mapper for an EL expression
* Instead of a global mapper, a mapper is used for ecah call to EL
* evaluator, thus avoiding the prefix overlapping and redefinition
* issues.
*/
public class ELFunctionMapper {
static private int currFunc = 0;
private ErrorDispatcher err;
StringBuffer ds;
StringBuffer ss;
public static void map(Compiler compiler, Node.Nodes page)
throws JasperException {
currFunc = 0;
ELFunctionMapper map = new ELFunctionMapper();
map.err = compiler.getErrorDispatcher();
map.ds = new StringBuffer();
map.ss = new StringBuffer();
map.ds.append("static {\n");
page.visit(map.new ELFunctionVisitor());
map.ds.append("}\n");
// Append the declarations to the root node
Node root = page.getRoot();
new Node.Declaration(map.ss.toString(), root.getStart(), root);
new Node.Declaration(map.ds.toString(), root.getStart(), root);
}
class ELFunctionVisitor extends Node.Visitor {
public void visit(Node.ParamAction n) throws JasperException {
doMap(n.getValue());
}
public void visit(Node.IncludeAction n) throws JasperException {
doMap(n.getPage());
}
public void visit(Node.ForwardAction n) throws JasperException {
doMap(n.getPage());
}
public void visit(Node.SetProperty n) throws JasperException {
doMap(n.getValue());
}
public void visit(Node.UseBean n) throws JasperException {
doMap(n.getBeanName());
}
public void visit(Node.PlugIn n) throws JasperException {
doMap(n.getHeight());
doMap(n.getWidth());
}
public void visit(Node.JspElement n) throws JasperException {
Node.JspAttribute[] attrs = n.getJspAttributes();
for (int i = 0; i < attrs.length; i++) {
doMap(attrs[i]);
}
doMap(n.getNameAttribute());
}
public void visit(Node.CustomTag n) throws JasperException {
Node.JspAttribute[] attrs = n.getJspAttributes();
for (int i = 0; i < attrs.length; i++) {
doMap(attrs[i]);
}
}
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());
}
}
private void doMap(ELNode.Nodes el)
throws JasperException {
class Fvisitor extends ELNode.Visitor {
ArrayList funcs = new ArrayList();
public void visit(ELNode.Function n) throws JasperException {
funcs.add(n);
}
}
if (el == null) {
return;
}
// First locate all functions in this expression
Fvisitor fv = new Fvisitor();
el.visit(fv);
ArrayList functions = fv.funcs;
// TODO Some optimization here: if the fmap has only one entry,
// if it was generated before, use it.
if (functions.size() == 0) {
return;
}
// Generate declaration for the map statically
String decName = getMapName();
ss.append("static private org.apache.jasper.runtime.ProtectedFunctionMapper " + decName + ";\n");
ds.append(" " + decName + " = org.apache.jasper.runtime.ProtectedFunctionMapper.getInstance();\n");
for (int i = 0; i < functions.size(); i++) {
ELNode.Function f = (ELNode.Function)functions.get(i);
FunctionInfo funcInfo = f.getFunctionInfo();
String key = f.getPrefix()+ ":" + f.getName();
ds.append(" " + decName + ".mapFunction(\"" + key + "\", " +
funcInfo.getFunctionClass() + ".class, " +
'\"' + getMethod(f) + "\", " +
"new Class[] {" + getParameters(f) + "}" +
");\n");
}
el.setMapName(decName);
}
private String getMapName() {
return "_jspx_fnmap_" + currFunc++;
}
private String getMethod(ELNode.Function func)
throws JasperException {
FunctionInfo funcInfo = func.getFunctionInfo();
String signature = funcInfo.getFunctionSignature();
int start = signature.indexOf(' ');
if (start < 0) {
err.jspError("jsp.error.tld.fn.invalid.signature",
func.getPrefix(), func.getName());
}
int end = signature.indexOf('(');
if (end < 0) {
err.jspError("jsp.error.tld.fn.invalid.signature.parenexpected",
func.getPrefix(), func.getName());
}
return signature.substring(start+1, end).trim();
}
private String getParameters(ELNode.Function func)
throws JasperException {
FunctionInfo funcInfo = func.getFunctionInfo();
StringBuffer buf = new StringBuffer();
String signature = funcInfo.getFunctionSignature();
// Signature is of the form
// <return-type> S <method-name S? '('
// < <arg-type> ( ',' <arg-type> )* )? ')'
int start = signature.indexOf('(') + 1;
boolean lastArg = false;
while (true) {
int p = signature.indexOf(',', start);
if (p < 0) {
p = signature.indexOf(')', start);
if (p < 0) {
err.jspError("jsp.error.tld.fn.invalid.signature",
func.getPrefix(), func.getName());
}
lastArg = true;
}
String arg = signature.substring(start, p).trim();
buf.append(arg + ".class");
if (lastArg) {
break;
}
buf.append(',');
start = p+1;
}
return buf.toString();
}
}
}
1.1 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/ELNode.java
Index: ELNode.java
===================================================================
/* ========================================================================= *
* *
* The Apache Software License, Version 1.1 *
* *
* Copyright (c) 1999, 2000, 2001 The Apache Software Foundation. *
* All rights reserved. *
* *
* ========================================================================= *
* *
* Redistribution and use in source and binary forms, with or without modi- *
* fication, are permitted provided that the following conditions are met: *
* *
* 1. Redistributions of source code must retain the above copyright notice *
* notice, this list of conditions and the following disclaimer. *
* *
* 2. Redistributions in binary form must reproduce the above copyright *
* notice, this list of conditions and the following disclaimer in the *
* documentation and/or other materials provided with the distribution. *
* *
* 3. The end-user documentation included with the redistribution, if any, *
* must include the following acknowlegement: *
* *
* "This product includes software developed by the Apache Software *
* Foundation <http://www.apache.org/>." *
* *
* Alternately, this acknowlegement may appear in the software itself, if *
* and wherever such third-party acknowlegements normally appear. *
* *
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software *
* Foundation" must not be used to endorse or promote products derived *
* from this software without prior written permission. For written *
* permission, please contact <ap...@apache.org>. *
* *
* 5. Products derived from this software may not be called "Apache" nor may *
* "Apache" appear in their names without prior written permission of the *
* Apache Software Foundation. *
* *
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES *
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY *
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY *
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS *
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, *
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *
* POSSIBILITY OF SUCH DAMAGE. *
* *
* ========================================================================= *
* *
* This software consists of voluntary contributions made by many indivi- *
* duals on behalf of the Apache Software Foundation. For more information *
* on the Apache Software Foundation, please see <http://www.apache.org/>. *
* *
* ========================================================================= */
package org.apache.jasper.compiler;
import java.util.*;
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.
*/
abstract class ELNode {
abstract public void accept(Visitor v) throws JasperException;
/**
* Child classes
*/
/**
* Represents an EL expression: anything in ${ and }.
*/
public static class Root extends ELNode {
private ELNode.Nodes expr;
Root(ELNode.Nodes expr) {
this.expr = expr;
}
public void accept(Visitor v) throws JasperException {
v.visit(this);
}
public ELNode.Nodes getExpression() {
return expr;
}
}
/**
* Represents text outside of EL expression.
*/
public static class Text extends ELNode {
private String text;
Text(String text) {
this.text = text;
}
public void accept(Visitor v) throws JasperException {
v.visit(this);
}
public String getText() {
return text;
}
}
/**
* Represents anything else EL expression, including function arguments etc
*/
public static class ELText extends ELNode {
private String text;
ELText(String text) {
this.text = text;
}
public void accept(Visitor v) throws JasperException {
v.visit(this);
}
public String getText() {
return text;
}
}
/**
* Represents a function
* Currently only the prefix and function name, but not its arguments.
*/
public static class Function extends ELNode {
String prefix;
String name;
FunctionInfo functionInfo;
Function(String prefix, String name) {
this.prefix = prefix;
this.name = name;
}
public void accept(Visitor v) throws JasperException {
v.visit(this);
}
public String getPrefix() {
return prefix;
}
public String getName() {
return name;
}
public void setFunctionInfo(FunctionInfo f) {
this.functionInfo = f;
}
public FunctionInfo getFunctionInfo() {
return functionInfo;
}
}
/**
* 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.
*/
String mapName = null;
private List 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
*/
public void visit(Visitor v) throws JasperException {
Iterator iter = list.iterator();
while (iter.hasNext()) {
ELNode n = (ELNode) iter.next();
n.accept(v);
}
}
public Iterator iterator() {
return list.iterator();
}
public boolean isEmpty() {
return list.size() == 0;
}
/**
* @return true if the expression contains a ${...}
*/
public boolean containsEL() {
Iterator iter = list.iterator();
while (iter.hasNext()) {
ELNode n = (ELNode) iter.next();
if (n instanceof Root) {
return true;
}
}
return false;
}
public void setMapName(String name) {
this.mapName = name;
}
public String getMapName() {
return mapName;
}
}
public static class Visitor {
public void visit(Root n) throws JasperException {
n.getExpression().visit(this);
}
public void visit(Function n) throws JasperException {
}
public void visit(Text n) throws JasperException {
}
public void visit(ELText n) throws JasperException {
}
}
}
1.1 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/ELParser.java
Index: ELParser.java
===================================================================
/* ========================================================================= *
* *
* The Apache Software License, Version 1.1 *
* *
* Copyright (c) 1999, 2000, 2001 The Apache Software Foundation. *
* All rights reserved. *
* *
* ========================================================================= *
* *
* Redistribution and use in source and binary forms, with or without modi- *
* fication, are permitted provided that the following conditions are met: *
* *
* 1. Redistributions of source code must retain the above copyright notice *
* notice, this list of conditions and the following disclaimer. *
* *
* 2. Redistributions in binary form must reproduce the above copyright *
* notice, this list of conditions and the following disclaimer in the *
* documentation and/or other materials provided with the distribution. *
* *
* 3. The end-user documentation included with the redistribution, if any, *
* must include the following acknowlegement: *
* *
* "This product includes software developed by the Apache Software *
* Foundation <http://www.apache.org/>." *
* *
* Alternately, this acknowlegement may appear in the software itself, if *
* and wherever such third-party acknowlegements normally appear. *
* *
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software *
* Foundation" must not be used to endorse or promote products derived *
* from this software without prior written permission. For written *
* permission, please contact <ap...@apache.org>. *
* *
* 5. Products derived from this software may not be called "Apache" nor may *
* "Apache" appear in their names without prior written permission of the *
* Apache Software Foundation. *
* *
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES *
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY *
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY *
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS *
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, *
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *
* POSSIBILITY OF SUCH DAMAGE. *
* *
* ========================================================================= *
* *
* This software consists of voluntary contributions made by many indivi- *
* duals on behalf of the Apache Software Foundation. For more information *
* on the Apache Software Foundation, please see <http://www.apache.org/>. *
* *
* ========================================================================= */
package org.apache.jasper.compiler;
/**
* This class implements a parser for EL expressions.
*
* It takes strings of the form xxx${..}yyy${..}zzz etc, and turn it into
* a ELNode.Nodes.
*
* Currently, it only handles text outside ${..} and functions in ${ ..}.
*/
public class ELParser {
private Token curToken; // current token
private ELNode.Nodes expr;
private ELNode.Nodes ELexpr;
private int index; // Current index of the expression
private String expression; // The EL expression
private boolean escapeBS; // is '\' an escape char in text outside EL?
public ELParser(String expression) {
index = 0;
this.expression = expression;
expr = new ELNode.Nodes();
}
public static ELNode.Nodes parse(String expression) {
ELParser parser = new ELParser(expression);
while (parser.hasNextChar()) {
String text = parser.skipUntilEL();
if (text.length() > 0) {
parser.expr.add(new ELNode.Text(text));
}
ELNode.Nodes elexpr = parser.parseEL();
if (! elexpr.isEmpty()) {
parser.expr.add(new ELNode.Root(elexpr));
}
}
return parser.expr;
}
/**
* Parse EL into functions and else.
*@return An ELLNode.Nodes representing the EL expression
* TODO: this should be rewritten for a full parser.
*/
private ELNode.Nodes parseEL() {
StringBuffer buf = new StringBuffer();
ELexpr = new ELNode.Nodes();
while (hasNext()) {
curToken = nextToken();
if (curToken instanceof Char) {
if (curToken.toChar() == '}') {
break;
}
buf.append(curToken.toChar());
} else {
// Output whatever is in buffer
if (buf.length() > 0) {
ELexpr.add(new ELNode.ELText(buf.toString()));
}
if (!parseFunction()) {
ELexpr.add(new ELNode.ELText(curToken.toString()));
}
}
}
if (buf.length() > 0) {
ELexpr.add(new ELNode.ELText(buf.toString()));
}
return ELexpr;
}
/**
* Parse for a function
* FunctionInvokation ::= (identifier ':')? identifier '('
* (Expression (,Expression)*)? ')'
* Note: currently we don't parse arguments
*/
private boolean parseFunction() {
if (! (curToken instanceof Id)) {
return false;
}
String s1 = null;
String s2 = curToken.toString();
int mark = getIndex();
if (hasNext()) {
Token t = nextToken();
if (t.toChar() == ':') {
if (hasNext()) {
Token t2 = nextToken();
if (t2 instanceof Id) {
s1 = s2;
s2 = t2.toString();
if (hasNext()) {
t = nextToken();
}
}
}
}
if (t.toChar() == '(') {
ELexpr.add(new ELNode.Function(s1, s2));
return true;
}
}
setIndex(mark);
return false;
}
/**
* Skip until an EL expression is reached.
* @return The text string up to the EL expression
*/
private String skipUntilEL() {
char prev = 0;
StringBuffer buf = new StringBuffer();
while (hasNextChar()) {
char ch = nextChar();
if (prev == '\\') {
prev = 0;
if (ch == '\\') {
buf.append('\\');
if (!escapeBS)
prev = '\\';
} else if (ch == '$') {
buf.append('$');
}
// else error!
} else if (prev == '$') {
if (ch == '{') {
prev = 0;
break;
}
buf.append('$');
buf.append(ch);
} else if (ch == '\\' || ch == '$') {
prev = ch;
} else {
buf.append(ch);
}
}
if (prev != 0) {
buf.append(prev);
}
return buf.toString();
}
private boolean hasNext() {
skipSpaces();
return hasNextChar();
}
private Token nextToken() {
skipSpaces();
if (hasNextChar()) {
char ch = nextChar();
if (Character.isJavaIdentifierStart(ch)) {
StringBuffer buf = new StringBuffer();
buf.append(ch);
while ((ch = peekChar()) != -1 &&
Character.isJavaIdentifierPart(ch)) {
buf.append(ch);
nextChar();
}
return new Id(buf.toString());
}
if (ch == '\'' || ch == '"') {
return parseQuotedChars(ch);
} else {
// For now...
return new Char(ch);
}
}
return null;
}
private Token parseQuotedChars(char quote) {
StringBuffer buf = new StringBuffer();
buf.append(quote);
while (hasNextChar()) {
char ch = nextChar();
if (ch == '\\') {
ch = nextChar();
if (ch == '\\' || ch == quote) {
buf.append(ch);
}
// else error!
} else if (ch == quote) {
buf.append(ch);
break;
} else {
buf.append(ch);
}
}
return new QuotedString(buf.toString());
}
private void skipSpaces() {
while (hasNextChar()) {
if (expression.charAt(index) > ' ')
break;
index++;
}
}
private boolean hasNextChar() {
return index < expression.length();
}
private char nextChar() {
if (index >= expression.length()) {
return (char)-1;
}
return expression.charAt(index++);
}
private char peekChar() {
if (index >= expression.length()) {
return (char)-1;
}
return expression.charAt(index);
}
private int getIndex() {
return index;
}
private void setIndex(int i) {
index = i;
}
private static class Token {
char toChar() {
return 0;
}
public String toString() {
return "";
}
}
private static class Id extends Token {
String id;
Id(String id) {
this.id = id;
}
public String toString() {
return id;
}
}
private static class Char extends Token {
private char ch;
Char(char ch) {
this.ch = ch;
}
char toChar() {
return ch;
}
public String toString() {
return (new Character(ch)).toString();
}
}
private static class QuotedString extends Token {
private String value;
QuotedString(String v) {
this.value = v;
}
public String toString() {
return value;
}
}
}
1.105 +3 -2 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/resources/messages.properties
Index: messages.properties
===================================================================
RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/resources/messages.properties,v
retrieving revision 1.104
retrieving revision 1.105
diff -u -r1.104 -r1.105
--- messages.properties 6 Mar 2003 20:21:46 -0000 1.104
+++ messages.properties 19 Mar 2003 20:51:35 -0000 1.105
@@ -374,4 +374,5 @@
jsp.error.attribute.null_name=Null attribute name
jsp.error.jsptext.badcontent=\'<\', when appears in the body of <jsp:text>, must be encapsulated within a CDATA
jsp.error.jsproot.version.invalid=Invalid version number: \"{0}\", must be \"1.2\" or \"2.0\"
-
+jsp.error.noFunctionPrefix=The function {0} must be used with a prefix when a default namespace is not specified
+jsp.error.noFunction=The function {0} is cannot be located with the specified prefix
---------------------------------------------------------------------
To unsubscribe, e-mail: tomcat-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tomcat-dev-help@jakarta.apache.org