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=\'&lt;\', when appears in the body of &lt;jsp:text&gt;, 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