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 <[EMAIL PROTECTED]>.                        *
   *                                                                           *
   * 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 <[EMAIL PROTECTED]>.                        *
   *                                                                           *
   * 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 <[EMAIL PROTECTED]>.                        *
   *                                                                           *
   * 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.
       [EMAIL PROTECTED] 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: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to