Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » jasper » compiler » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    * 
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    * 
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   package org.apache.jasper.compiler;
   19   
   20   import java.lang.reflect.Method;
   21   import java.util.ArrayList;
   22   import java.util.HashMap;
   23   import java.util.Hashtable;
   24   import java.util.Iterator;
   25   
   26   import javax.el.ELException;
   27   import javax.el.ExpressionFactory;
   28   import javax.el.FunctionMapper;
   29   import javax.servlet.jsp.tagext.FunctionInfo;
   30   import javax.servlet.jsp.tagext.JspFragment;
   31   import javax.servlet.jsp.tagext.PageData;
   32   import javax.servlet.jsp.tagext.TagAttributeInfo;
   33   import javax.servlet.jsp.tagext.TagData;
   34   import javax.servlet.jsp.tagext.TagExtraInfo;
   35   import javax.servlet.jsp.tagext.TagInfo;
   36   import javax.servlet.jsp.tagext.TagLibraryInfo;
   37   import javax.servlet.jsp.tagext.ValidationMessage;
   38   
   39   import org.apache.el.lang.ELSupport;
   40   import org.apache.jasper.Constants;
   41   import org.apache.jasper.JasperException;
   42   import org.apache.jasper.el.ELContextImpl;
   43   import org.xml.sax.Attributes;
   44   
   45   /**
   46    * Performs validation on the page elements. Attributes are checked for
   47    * mandatory presence, entry value validity, and consistency. As a side effect,
   48    * some page global value (such as those from page direcitves) are stored, for
   49    * later use.
   50    * 
   51    * @author Kin-man Chung
   52    * @author Jan Luehe
   53    * @author Shawn Bayern
   54    * @author Mark Roth
   55    */
   56   class Validator {
   57   
   58       /**
   59        * A visitor to validate and extract page directive info
   60        */
   61       static class DirectiveVisitor extends Node.Visitor {
   62   
   63           private PageInfo pageInfo;
   64   
   65           private ErrorDispatcher err;
   66   
   67           private static final JspUtil.ValidAttribute[] pageDirectiveAttrs = {
   68               new JspUtil.ValidAttribute("language"),
   69               new JspUtil.ValidAttribute("extends"),
   70               new JspUtil.ValidAttribute("import"),
   71               new JspUtil.ValidAttribute("session"),
   72               new JspUtil.ValidAttribute("buffer"),
   73               new JspUtil.ValidAttribute("autoFlush"),
   74               new JspUtil.ValidAttribute("isThreadSafe"),
   75               new JspUtil.ValidAttribute("info"),
   76               new JspUtil.ValidAttribute("errorPage"),
   77               new JspUtil.ValidAttribute("isErrorPage"),
   78               new JspUtil.ValidAttribute("contentType"),
   79               new JspUtil.ValidAttribute("pageEncoding"),
   80               new JspUtil.ValidAttribute("isELIgnored"),
   81               new JspUtil.ValidAttribute("deferredSyntaxAllowedAsLiteral"),
   82               new JspUtil.ValidAttribute("trimDirectiveWhitespaces")
   83           };
   84   
   85           private boolean pageEncodingSeen = false;
   86   
   87           /*
   88            * Constructor
   89            */
   90           DirectiveVisitor(Compiler compiler) throws JasperException {
   91               this.pageInfo = compiler.getPageInfo();
   92               this.err = compiler.getErrorDispatcher();
   93           }
   94   
   95           public void visit(Node.IncludeDirective n) throws JasperException {
   96               // Since pageDirectiveSeen flag only applies to the Current page
   97               // save it here and restore it after the file is included.
   98               boolean pageEncodingSeenSave = pageEncodingSeen;
   99               pageEncodingSeen = false;
  100               visitBody(n);
  101               pageEncodingSeen = pageEncodingSeenSave;
  102           }
  103   
  104           public void visit(Node.PageDirective n) throws JasperException {
  105   
  106               JspUtil.checkAttributes("Page directive", n, pageDirectiveAttrs,
  107                       err);
  108   
  109               // JSP.2.10.1
  110               Attributes attrs = n.getAttributes();
  111               for (int i = 0; attrs != null && i < attrs.getLength(); i++) {
  112                   String attr = attrs.getQName(i);
  113                   String value = attrs.getValue(i);
  114   
  115                   if ("language".equals(attr)) {
  116                       if (pageInfo.getLanguage(false) == null) {
  117                           pageInfo.setLanguage(value, n, err, true);
  118                       } else if (!pageInfo.getLanguage(false).equals(value)) {
  119                           err.jspError(n, "jsp.error.page.conflict.language",
  120                                   pageInfo.getLanguage(false), value);
  121                       }
  122                   } else if ("extends".equals(attr)) {
  123                       if (pageInfo.getExtends(false) == null) {
  124                           pageInfo.setExtends(value, n);
  125                       } else if (!pageInfo.getExtends(false).equals(value)) {
  126                           err.jspError(n, "jsp.error.page.conflict.extends",
  127                                   pageInfo.getExtends(false), value);
  128                       }
  129                   } else if ("contentType".equals(attr)) {
  130                       if (pageInfo.getContentType() == null) {
  131                           pageInfo.setContentType(value);
  132                       } else if (!pageInfo.getContentType().equals(value)) {
  133                           err.jspError(n, "jsp.error.page.conflict.contenttype",
  134                                   pageInfo.getContentType(), value);
  135                       }
  136                   } else if ("session".equals(attr)) {
  137                       if (pageInfo.getSession() == null) {
  138                           pageInfo.setSession(value, n, err);
  139                       } else if (!pageInfo.getSession().equals(value)) {
  140                           err.jspError(n, "jsp.error.page.conflict.session",
  141                                   pageInfo.getSession(), value);
  142                       }
  143                   } else if ("buffer".equals(attr)) {
  144                       if (pageInfo.getBufferValue() == null) {
  145                           pageInfo.setBufferValue(value, n, err);
  146                       } else if (!pageInfo.getBufferValue().equals(value)) {
  147                           err.jspError(n, "jsp.error.page.conflict.buffer",
  148                                   pageInfo.getBufferValue(), value);
  149                       }
  150                   } else if ("autoFlush".equals(attr)) {
  151                       if (pageInfo.getAutoFlush() == null) {
  152                           pageInfo.setAutoFlush(value, n, err);
  153                       } else if (!pageInfo.getAutoFlush().equals(value)) {
  154                           err.jspError(n, "jsp.error.page.conflict.autoflush",
  155                                   pageInfo.getAutoFlush(), value);
  156                       }
  157                   } else if ("isThreadSafe".equals(attr)) {
  158                       if (pageInfo.getIsThreadSafe() == null) {
  159                           pageInfo.setIsThreadSafe(value, n, err);
  160                       } else if (!pageInfo.getIsThreadSafe().equals(value)) {
  161                           err.jspError(n, "jsp.error.page.conflict.isthreadsafe",
  162                                   pageInfo.getIsThreadSafe(), value);
  163                       }
  164                   } else if ("isELIgnored".equals(attr)) {
  165                       if (pageInfo.getIsELIgnored() == null) {
  166                           pageInfo.setIsELIgnored(value, n, err, true);
  167                       } else if (!pageInfo.getIsELIgnored().equals(value)) {
  168                           err.jspError(n, "jsp.error.page.conflict.iselignored",
  169                                   pageInfo.getIsELIgnored(), value);
  170                       }
  171                   } else if ("isErrorPage".equals(attr)) {
  172                       if (pageInfo.getIsErrorPage() == null) {
  173                           pageInfo.setIsErrorPage(value, n, err);
  174                       } else if (!pageInfo.getIsErrorPage().equals(value)) {
  175                           err.jspError(n, "jsp.error.page.conflict.iserrorpage",
  176                                   pageInfo.getIsErrorPage(), value);
  177                       }
  178                   } else if ("errorPage".equals(attr)) {
  179                       if (pageInfo.getErrorPage() == null) {
  180                           pageInfo.setErrorPage(value);
  181                       } else if (!pageInfo.getErrorPage().equals(value)) {
  182                           err.jspError(n, "jsp.error.page.conflict.errorpage",
  183                                   pageInfo.getErrorPage(), value);
  184                       }
  185                   } else if ("info".equals(attr)) {
  186                       if (pageInfo.getInfo() == null) {
  187                           pageInfo.setInfo(value);
  188                       } else if (!pageInfo.getInfo().equals(value)) {
  189                           err.jspError(n, "jsp.error.page.conflict.info",
  190                                   pageInfo.getInfo(), value);
  191                       }
  192                   } else if ("pageEncoding".equals(attr)) {
  193                       if (pageEncodingSeen)
  194                           err.jspError(n, "jsp.error.page.multi.pageencoding");
  195                       // 'pageEncoding' can occur at most once per file
  196                       pageEncodingSeen = true;
  197                       String actual = comparePageEncodings(value, n);
  198                       n.getRoot().setPageEncoding(actual);
  199                   } else if ("deferredSyntaxAllowedAsLiteral".equals(attr)) {
  200                       if (pageInfo.getDeferredSyntaxAllowedAsLiteral() == null) {
  201                           pageInfo.setDeferredSyntaxAllowedAsLiteral(value, n,
  202                                   err, true);
  203                       } else if (!pageInfo.getDeferredSyntaxAllowedAsLiteral()
  204                               .equals(value)) {
  205                           err
  206                                   .jspError(
  207                                           n,
  208                                           "jsp.error.page.conflict.deferredsyntaxallowedasliteral",
  209                                           pageInfo
  210                                                   .getDeferredSyntaxAllowedAsLiteral(),
  211                                           value);
  212                       }
  213                   } else if ("trimDirectiveWhitespaces".equals(attr)) {
  214                       if (pageInfo.getTrimDirectiveWhitespaces() == null) {
  215                           pageInfo.setTrimDirectiveWhitespaces(value, n, err,
  216                                   true);
  217                       } else if (!pageInfo.getTrimDirectiveWhitespaces().equals(
  218                               value)) {
  219                           err
  220                                   .jspError(
  221                                           n,
  222                                           "jsp.error.page.conflict.trimdirectivewhitespaces",
  223                                           pageInfo.getTrimDirectiveWhitespaces(),
  224                                           value);
  225                       }
  226                   }
  227               }
  228   
  229               // Check for bad combinations
  230               if (pageInfo.getBuffer() == 0 && !pageInfo.isAutoFlush())
  231                   err.jspError(n, "jsp.error.page.badCombo");
  232   
  233               // Attributes for imports for this node have been processed by
  234               // the parsers, just add them to pageInfo.
  235               pageInfo.addImports(n.getImports());
  236           }
  237   
  238           public void visit(Node.TagDirective n) throws JasperException {
  239               // Note: Most of the validation is done in TagFileProcessor
  240               // when it created a TagInfo object from the
  241               // tag file in which the directive appeared.
  242   
  243               // This method does additional processing to collect page info
  244   
  245               Attributes attrs = n.getAttributes();
  246               for (int i = 0; attrs != null && i < attrs.getLength(); i++) {
  247                   String attr = attrs.getQName(i);
  248                   String value = attrs.getValue(i);
  249   
  250                   if ("language".equals(attr)) {
  251                       if (pageInfo.getLanguage(false) == null) {
  252                           pageInfo.setLanguage(value, n, err, false);
  253                       } else if (!pageInfo.getLanguage(false).equals(value)) {
  254                           err.jspError(n, "jsp.error.tag.conflict.language",
  255                                   pageInfo.getLanguage(false), value);
  256                       }
  257                   } else if ("isELIgnored".equals(attr)) {
  258                       if (pageInfo.getIsELIgnored() == null) {
  259                           pageInfo.setIsELIgnored(value, n, err, false);
  260                       } else if (!pageInfo.getIsELIgnored().equals(value)) {
  261                           err.jspError(n, "jsp.error.tag.conflict.iselignored",
  262                                   pageInfo.getIsELIgnored(), value);
  263                       }
  264                   } else if ("pageEncoding".equals(attr)) {
  265                       if (pageEncodingSeen)
  266                           err.jspError(n, "jsp.error.tag.multi.pageencoding");
  267                       pageEncodingSeen = true;
  268                       compareTagEncodings(value, n);
  269                       n.getRoot().setPageEncoding(value);
  270                   } else if ("deferredSyntaxAllowedAsLiteral".equals(attr)) {
  271                       if (pageInfo.getDeferredSyntaxAllowedAsLiteral() == null) {
  272                           pageInfo.setDeferredSyntaxAllowedAsLiteral(value, n,
  273                                   err, false);
  274                       } else if (!pageInfo.getDeferredSyntaxAllowedAsLiteral()
  275                               .equals(value)) {
  276                           err
  277                                   .jspError(
  278                                           n,
  279                                           "jsp.error.tag.conflict.deferredsyntaxallowedasliteral",
  280                                           pageInfo
  281                                                   .getDeferredSyntaxAllowedAsLiteral(),
  282                                           value);
  283                       }
  284                   } else if ("trimDirectiveWhitespaces".equals(attr)) {
  285                       if (pageInfo.getTrimDirectiveWhitespaces() == null) {
  286                           pageInfo.setTrimDirectiveWhitespaces(value, n, err,
  287                                   false);
  288                       } else if (!pageInfo.getTrimDirectiveWhitespaces().equals(
  289                               value)) {
  290                           err
  291                                   .jspError(
  292                                           n,
  293                                           "jsp.error.tag.conflict.trimdirectivewhitespaces",
  294                                           pageInfo.getTrimDirectiveWhitespaces(),
  295                                           value);
  296                       }
  297                   }
  298               }
  299   
  300               // Attributes for imports for this node have been processed by
  301               // the parsers, just add them to pageInfo.
  302               pageInfo.addImports(n.getImports());
  303           }
  304   
  305           public void visit(Node.AttributeDirective n) throws JasperException {
  306               // Do nothing, since this attribute directive has already been
  307               // validated by TagFileProcessor when it created a TagInfo object
  308               // from the tag file in which the directive appeared
  309           }
  310   
  311           public void visit(Node.VariableDirective n) throws JasperException {
  312               // Do nothing, since this variable directive has already been
  313               // validated by TagFileProcessor when it created a TagInfo object
  314               // from the tag file in which the directive appeared
  315           }
  316   
  317           /*
  318            * Compares page encodings specified in various places, and throws
  319            * exception in case of page encoding mismatch.
  320            * 
  321            * @param pageDirEnc The value of the pageEncoding attribute of the page
  322            * directive @param pageDir The page directive node
  323            * 
  324            * @throws JasperException in case of page encoding mismatch
  325            */
  326           private String comparePageEncodings(String pageDirEnc,
  327                   Node.PageDirective pageDir) throws JasperException {
  328   
  329               Node.Root root = pageDir.getRoot();
  330               String configEnc = root.getJspConfigPageEncoding();
  331   
  332               /*
  333                * Compare the 'pageEncoding' attribute of the page directive with
  334                * the encoding specified in the JSP config element whose URL
  335                * pattern matches this page. Treat "UTF-16", "UTF-16BE", and
  336                * "UTF-16LE" as identical.
  337                */
  338               if (configEnc != null) {
  339                   if (!pageDirEnc.equals(configEnc)
  340                           && (!pageDirEnc.startsWith("UTF-16") || !configEnc
  341                                   .startsWith("UTF-16"))) {
  342                       err.jspError(pageDir,
  343                               "jsp.error.config_pagedir_encoding_mismatch",
  344                               configEnc, pageDirEnc);
  345                   } else {
  346                       return configEnc;
  347                   }
  348               }
  349   
  350               /*
  351                * Compare the 'pageEncoding' attribute of the page directive with
  352                * the encoding specified in the XML prolog (only for XML syntax,
  353                * and only if JSP document contains XML prolog with encoding
  354                * declaration). Treat "UTF-16", "UTF-16BE", and "UTF-16LE" as
  355                * identical.
  356                */
  357               if ((root.isXmlSyntax() && root.isEncodingSpecifiedInProlog()) || root.isBomPresent()) {
  358                   String pageEnc = root.getPageEncoding();
  359                   if (!pageDirEnc.equals(pageEnc)
  360                           && (!pageDirEnc.startsWith("UTF-16") || !pageEnc
  361                                   .startsWith("UTF-16"))) {
  362                       err.jspError(pageDir,
  363                               "jsp.error.prolog_pagedir_encoding_mismatch",
  364                               pageEnc, pageDirEnc);
  365                   } else {
  366                       return pageEnc;
  367                   }
  368               }
  369               
  370               return pageDirEnc;
  371           }
  372           
  373           /*
  374            * Compares page encodings specified in various places, and throws
  375            * exception in case of page encoding mismatch.
  376            * 
  377            * @param pageDirEnc The value of the pageEncoding attribute of the page
  378            * directive @param pageDir The page directive node
  379            * 
  380            * @throws JasperException in case of page encoding mismatch
  381            */
  382           private void compareTagEncodings(String pageDirEnc,
  383                   Node.TagDirective pageDir) throws JasperException {
  384   
  385               Node.Root root = pageDir.getRoot();
  386   
  387               /*
  388                * Compare the 'pageEncoding' attribute of the page directive with
  389                * the encoding specified in the XML prolog (only for XML syntax,
  390                * and only if JSP document contains XML prolog with encoding
  391                * declaration). Treat "UTF-16", "UTF-16BE", and "UTF-16LE" as
  392                * identical.
  393                */
  394               if ((root.isXmlSyntax() && root.isEncodingSpecifiedInProlog()) || root.isBomPresent()) {
  395                   String pageEnc = root.getPageEncoding();
  396                   if (!pageDirEnc.equals(pageEnc)
  397                           && (!pageDirEnc.startsWith("UTF-16") || !pageEnc
  398                                   .startsWith("UTF-16"))) {
  399                       err.jspError(pageDir,
  400                               "jsp.error.prolog_pagedir_encoding_mismatch",
  401                               pageEnc, pageDirEnc);
  402                   }
  403               }
  404           }
  405   
  406       }
  407   
  408       /**
  409        * A visitor for validating nodes other than page directives
  410        */
  411       static class ValidateVisitor extends Node.Visitor {
  412   
  413           private PageInfo pageInfo;
  414   
  415           private ErrorDispatcher err;
  416   
  417           private TagInfo tagInfo;
  418   
  419           private ClassLoader loader;
  420   
  421           private final StringBuffer buf = new StringBuffer(32);
  422   
  423           private static final JspUtil.ValidAttribute[] jspRootAttrs = {
  424                   new JspUtil.ValidAttribute("xsi:schemaLocation"),
  425                   new JspUtil.ValidAttribute("version", true) };
  426   
  427           private static final JspUtil.ValidAttribute[] includeDirectiveAttrs = { new JspUtil.ValidAttribute(
  428                   "file", true) };
  429   
  430           private static final JspUtil.ValidAttribute[] taglibDirectiveAttrs = {
  431                   new JspUtil.ValidAttribute("uri"),
  432                   new JspUtil.ValidAttribute("tagdir"),
  433                   new JspUtil.ValidAttribute("prefix", true) };
  434   
  435           private static final JspUtil.ValidAttribute[] includeActionAttrs = {
  436                   new JspUtil.ValidAttribute("page", true, true),
  437                   new JspUtil.ValidAttribute("flush") };
  438   
  439           private static final JspUtil.ValidAttribute[] paramActionAttrs = {
  440                   new JspUtil.ValidAttribute("name", true),
  441                   new JspUtil.ValidAttribute("value", true, true) };
  442   
  443           private static final JspUtil.ValidAttribute[] forwardActionAttrs = { new JspUtil.ValidAttribute(
  444                   "page", true, true) };
  445   
  446           private static final JspUtil.ValidAttribute[] getPropertyAttrs = {
  447                   new JspUtil.ValidAttribute("name", true),
  448                   new JspUtil.ValidAttribute("property", true) };
  449   
  450           private static final JspUtil.ValidAttribute[] setPropertyAttrs = {
  451                   new JspUtil.ValidAttribute("name", true),
  452                   new JspUtil.ValidAttribute("property", true),
  453                   new JspUtil.ValidAttribute("value", false, true),
  454                   new JspUtil.ValidAttribute("param") };
  455   
  456           private static final JspUtil.ValidAttribute[] useBeanAttrs = {
  457                   new JspUtil.ValidAttribute("id", true),
  458                   new JspUtil.ValidAttribute("scope"),
  459                   new JspUtil.ValidAttribute("class"),
  460                   new JspUtil.ValidAttribute("type"),
  461                   new JspUtil.ValidAttribute("beanName", false, true) };
  462   
  463           private static final JspUtil.ValidAttribute[] plugInAttrs = {
  464                   new JspUtil.ValidAttribute("type", true),
  465                   new JspUtil.ValidAttribute("code", true),
  466                   new JspUtil.ValidAttribute("codebase"),
  467                   new JspUtil.ValidAttribute("align"),
  468                   new JspUtil.ValidAttribute("archive"),
  469                   new JspUtil.ValidAttribute("height", false, true),
  470                   new JspUtil.ValidAttribute("hspace"),
  471                   new JspUtil.ValidAttribute("jreversion"),
  472                   new JspUtil.ValidAttribute("name"),
  473                   new JspUtil.ValidAttribute("vspace"),
  474                   new JspUtil.ValidAttribute("width", false, true),
  475                   new JspUtil.ValidAttribute("nspluginurl"),
  476                   new JspUtil.ValidAttribute("iepluginurl") };
  477   
  478           private static final JspUtil.ValidAttribute[] attributeAttrs = {
  479                   new JspUtil.ValidAttribute("name", true),
  480                   new JspUtil.ValidAttribute("trim") };
  481   
  482           private static final JspUtil.ValidAttribute[] invokeAttrs = {
  483                   new JspUtil.ValidAttribute("fragment", true),
  484                   new JspUtil.ValidAttribute("var"),
  485                   new JspUtil.ValidAttribute("varReader"),
  486                   new JspUtil.ValidAttribute("scope") };
  487   
  488           private static final JspUtil.ValidAttribute[] doBodyAttrs = {
  489                   new JspUtil.ValidAttribute("var"),
  490                   new JspUtil.ValidAttribute("varReader"),
  491                   new JspUtil.ValidAttribute("scope") };
  492   
  493           private static final JspUtil.ValidAttribute[] jspOutputAttrs = {
  494                   new JspUtil.ValidAttribute("omit-xml-declaration"),
  495                   new JspUtil.ValidAttribute("doctype-root-element"),
  496                   new JspUtil.ValidAttribute("doctype-public"),
  497                   new JspUtil.ValidAttribute("doctype-system") };
  498   
  499           /*
  500            * Constructor
  501            */
  502           ValidateVisitor(Compiler compiler) {
  503               this.pageInfo = compiler.getPageInfo();
  504               this.err = compiler.getErrorDispatcher();
  505               this.tagInfo = compiler.getCompilationContext().getTagInfo();
  506               this.loader = compiler.getCompilationContext().getClassLoader();
  507           }
  508   
  509           public void visit(Node.JspRoot n) throws JasperException {
  510               JspUtil.checkAttributes("Jsp:root", n, jspRootAttrs, err);
  511               String version = n.getTextAttribute("version");
  512               if (!version.equals("1.2") && !version.equals("2.0") && !version.equals("2.1")) {
  513                   err.jspError(n, "jsp.error.jsproot.version.invalid", version);
  514               }
  515               visitBody(n);
  516           }
  517   
  518           public void visit(Node.IncludeDirective n) throws JasperException {
  519               JspUtil.checkAttributes("Include directive", n,
  520                       includeDirectiveAttrs, err);
  521               visitBody(n);
  522           }
  523   
  524           public void visit(Node.TaglibDirective n) throws JasperException {
  525               JspUtil.checkAttributes("Taglib directive", n,
  526                       taglibDirectiveAttrs, err);
  527               // Either 'uri' or 'tagdir' attribute must be specified
  528               String uri = n.getAttributeValue("uri");
  529               String tagdir = n.getAttributeValue("tagdir");
  530               if (uri == null && tagdir == null) {
  531                   err.jspError(n, "jsp.error.taglibDirective.missing.location");
  532               }
  533               if (uri != null && tagdir != null) {
  534                   err
  535                           .jspError(n,
  536                                   "jsp.error.taglibDirective.both_uri_and_tagdir");
  537               }
  538           }
  539   
  540           public void visit(Node.ParamAction n) throws JasperException {
  541               JspUtil.checkAttributes("Param action", n, paramActionAttrs, err);
  542               // make sure the value of the 'name' attribute is not a
  543               // request-time expression
  544               throwErrorIfExpression(n, "name", "jsp:param");
  545               n.setValue(getJspAttribute(null, "value", null, null, n
  546                       .getAttributeValue("value"), java.lang.String.class, n,
  547                       false));
  548               visitBody(n);
  549           }
  550   
  551           public void visit(Node.ParamsAction n) throws JasperException {
  552               // Make sure we've got at least one nested jsp:param
  553               Node.Nodes subElems = n.getBody();
  554               if (subElems == null) {
  555                   err.jspError(n, "jsp.error.params.emptyBody");
  556               }
  557               visitBody(n);
  558           }
  559   
  560           public void visit(Node.IncludeAction n) throws JasperException {
  561               JspUtil.checkAttributes("Include action", n, includeActionAttrs,
  562                       err);
  563               n.setPage(getJspAttribute(null, "page", null, null, n
  564                       .getAttributeValue("page"), java.lang.String.class, n,
  565                       false));
  566               visitBody(n);
  567           };
  568   
  569           public void visit(Node.ForwardAction n) throws JasperException {
  570               JspUtil.checkAttributes("Forward", n, forwardActionAttrs, err);
  571               n.setPage(getJspAttribute(null, "page", null, null, n
  572                       .getAttributeValue("page"), java.lang.String.class, n,
  573                       false));
  574               visitBody(n);
  575           }
  576   
  577           public void visit(Node.GetProperty n) throws JasperException {
  578               JspUtil.checkAttributes("GetProperty", n, getPropertyAttrs, err);
  579           }
  580   
  581           public void visit(Node.SetProperty n) throws JasperException {
  582               JspUtil.checkAttributes("SetProperty", n, setPropertyAttrs, err);
  583               String property = n.getTextAttribute("property");
  584               String param = n.getTextAttribute("param");
  585               String value = n.getAttributeValue("value");
  586   
  587               n.setValue(getJspAttribute(null, "value", null, null, value,
  588                       java.lang.Object.class, n, false));
  589   
  590               boolean valueSpecified = n.getValue() != null;
  591   
  592               if ("*".equals(property)) {
  593                   if (param != null || valueSpecified)
  594                       err.jspError(n, "jsp.error.setProperty.invalid");
  595   
  596               } else if (param != null && valueSpecified) {
  597                   err.jspError(n, "jsp.error.setProperty.invalid");
  598               }
  599   
  600               visitBody(n);
  601           }
  602   
  603           public void visit(Node.UseBean n) throws JasperException {
  604               JspUtil.checkAttributes("UseBean", n, useBeanAttrs, err);
  605   
  606               String name = n.getTextAttribute("id");
  607               String scope = n.getTextAttribute("scope");
  608               JspUtil.checkScope(scope, n, err);
  609               String className = n.getTextAttribute("class");
  610               String type = n.getTextAttribute("type");
  611               BeanRepository beanInfo = pageInfo.getBeanRepository();
  612   
  613               if (className == null && type == null)
  614                   err.jspError(n, "jsp.error.usebean.missingType");
  615   
  616               if (beanInfo.checkVariable(name))
  617                   err.jspError(n, "jsp.error.usebean.duplicate");
  618   
  619               if ("session".equals(scope) && !pageInfo.isSession())
  620                   err.jspError(n, "jsp.error.usebean.noSession");
  621   
  622               Node.JspAttribute jattr = getJspAttribute(null, "beanName", null,
  623                       null, n.getAttributeValue("beanName"),
  624                       java.lang.String.class, n, false);
  625               n.setBeanName(jattr);
  626               if (className != null && jattr != null)
  627                   err.jspError(n, "jsp.error.usebean.notBoth");
  628   
  629               if (className == null)
  630                   className = type;
  631   
  632               beanInfo.addBean(n, name, className, scope);
  633   
  634               visitBody(n);
  635           }
  636   
  637           public void visit(Node.PlugIn n) throws JasperException {
  638               JspUtil.checkAttributes("Plugin", n, plugInAttrs, err);
  639   
  640               throwErrorIfExpression(n, "type", "jsp:plugin");
  641               throwErrorIfExpression(n, "code", "jsp:plugin");
  642               throwErrorIfExpression(n, "codebase", "jsp:plugin");
  643               throwErrorIfExpression(n, "align", "jsp:plugin");
  644               throwErrorIfExpression(n, "archive", "jsp:plugin");
  645               throwErrorIfExpression(n, "hspace", "jsp:plugin");
  646               throwErrorIfExpression(n, "jreversion", "jsp:plugin");
  647               throwErrorIfExpression(n, "name", "jsp:plugin");
  648               throwErrorIfExpression(n, "vspace", "jsp:plugin");
  649               throwErrorIfExpression(n, "nspluginurl", "jsp:plugin");
  650               throwErrorIfExpression(n, "iepluginurl", "jsp:plugin");
  651   
  652               String type = n.getTextAttribute("type");
  653               if (type == null)
  654                   err.jspError(n, "jsp.error.plugin.notype");
  655               if (!type.equals("bean") && !type.equals("applet"))
  656                   err.jspError(n, "jsp.error.plugin.badtype");
  657               if (n.getTextAttribute("code") == null)
  658                   err.jspError(n, "jsp.error.plugin.nocode");
  659   
  660               Node.JspAttribute width = getJspAttribute(null, "width", null,
  661                       null, n.getAttributeValue("width"), java.lang.String.class,
  662                       n, false);
  663               n.setWidth(width);
  664   
  665               Node.JspAttribute height = getJspAttribute(null, "height", null,
  666                       null, n.getAttributeValue("height"),
  667                       java.lang.String.class, n, false);
  668               n.setHeight(height);
  669   
  670               visitBody(n);
  671           }
  672   
  673           public void visit(Node.NamedAttribute n) throws JasperException {
  674               JspUtil.checkAttributes("Attribute", n, attributeAttrs, err);
  675               visitBody(n);
  676           }
  677   
  678           public void visit(Node.JspBody n) throws JasperException {
  679               visitBody(n);
  680           }
  681   
  682           public void visit(Node.Declaration n) throws JasperException {
  683               if (pageInfo.isScriptingInvalid()) {
  684                   err.jspError(n.getStart(), "jsp.error.no.scriptlets");
  685               }
  686           }
  687   
  688           public void visit(Node.Expression n) throws JasperException {
  689               if (pageInfo.isScriptingInvalid()) {
  690                   err.jspError(n.getStart(), "jsp.error.no.scriptlets");
  691               }
  692           }
  693   
  694           public void visit(Node.Scriptlet n) throws JasperException {
  695               if (pageInfo.isScriptingInvalid()) {
  696                   err.jspError(n.getStart(), "jsp.error.no.scriptlets");
  697               }
  698           }
  699   
  700           public void visit(Node.ELExpression n) throws JasperException {
  701               // exit if we are ignoring EL all together
  702               if (pageInfo.isELIgnored())
  703                   return;
  704   
  705               // JSP.2.2 - '#{' not allowed in template text
  706               if (n.getType() == '#') {
  707                   if (!pageInfo.isDeferredSyntaxAllowedAsLiteral()
  708                           && (tagInfo == null 
  709                                   || ((tagInfo != null) && !(tagInfo.getTagLibrary().getRequiredVersion().equals("2.0")
  710                                           || tagInfo.getTagLibrary().getRequiredVersion().equals("1.2"))))) {
  711                       err.jspError(n, "jsp.error.el.template.deferred");
  712                   } else {
  713                       return;
  714                   }
  715               }
  716   
  717               // build expression
  718               StringBuffer expr = this.getBuffer();
  719               expr.append(n.getType()).append('{').append(n.getText())
  720                       .append('}');
  721               ELNode.Nodes el = ELParser.parse(expr.toString());
  722   
  723               // validate/prepare expression
  724               prepareExpression(el, n, expr.toString());
  725   
  726               // store it
  727               n.setEL(el);
  728           }
  729   
  730           public void visit(Node.UninterpretedTag n) throws JasperException {
  731               if (n.getNamedAttributeNodes().size() != 0) {
  732                   err.jspError(n, "jsp.error.namedAttribute.invalidUse");
  733               }
  734   
  735               Attributes attrs = n.getAttributes();
  736               if (attrs != null) {
  737                   int attrSize = attrs.getLength();
  738                   Node.JspAttribute[] jspAttrs = new Node.JspAttribute[attrSize];
  739                   for (int i = 0; i < attrSize; i++) {
  740                       jspAttrs[i] = getJspAttribute(null, attrs.getQName(i),
  741                               attrs.getURI(i), attrs.getLocalName(i), attrs
  742                                       .getValue(i), java.lang.Object.class, n,
  743                               false);
  744                   }
  745                   n.setJspAttributes(jspAttrs);
  746               }
  747   
  748               visitBody(n);
  749           }
  750   
  751           public void visit(Node.CustomTag n) throws JasperException {
  752   
  753               TagInfo tagInfo = n.getTagInfo();
  754               if (tagInfo == null) {
  755                   err.jspError(n, "jsp.error.missing.tagInfo", n.getQName());
  756               }
  757   
  758               /*
  759                * The bodyconet of a SimpleTag cannot be JSP.
  760                */
  761               if (n.implementsSimpleTag()
  762                       && tagInfo.getBodyContent().equalsIgnoreCase(
  763                               TagInfo.BODY_CONTENT_JSP)) {
  764                   err.jspError(n, "jsp.error.simpletag.badbodycontent", tagInfo
  765                           .getTagClassName());
  766               }
  767   
  768               /*
  769                * If the tag handler declares in the TLD that it supports dynamic
  770                * attributes, it also must implement the DynamicAttributes
  771                * interface.
  772                */
  773               if (tagInfo.hasDynamicAttributes()
  774                       && !n.implementsDynamicAttributes()) {
  775                   err.jspError(n, "jsp.error.dynamic.attributes.not.implemented",
  776                           n.getQName());
  777               }
  778   
  779               /*
  780                * Make sure all required attributes are present, either as
  781                * attributes or named attributes (<jsp:attribute>). Also make sure
  782                * that the same attribute is not specified in both attributes or
  783                * named attributes.
  784                */
  785               TagAttributeInfo[] tldAttrs = tagInfo.getAttributes();
  786               String customActionUri = n.getURI();
  787               Attributes attrs = n.getAttributes();
  788               int attrsSize = (attrs == null) ? 0 : attrs.getLength();
  789               for (int i = 0; i < tldAttrs.length; i++) {
  790                   String attr = null;
  791                   if (attrs != null) {
  792                       attr = attrs.getValue(tldAttrs[i].getName());
  793                       if (attr == null) {
  794                           attr = attrs.getValue(customActionUri, tldAttrs[i]
  795                                   .getName());
  796                       }
  797                   }
  798                   Node.NamedAttribute na = n.getNamedAttributeNode(tldAttrs[i]
  799                           .getName());
  800   
  801                   if (tldAttrs[i].isRequired() && attr == null && na == null) {
  802                       err.jspError(n, "jsp.error.missing_attribute", tldAttrs[i]
  803                               .getName(), n.getLocalName());
  804                   }
  805                   if (attr != null && na != null) {
  806                       err.jspError(n, "jsp.error.duplicate.name.jspattribute",
  807                               tldAttrs[i].getName());
  808                   }
  809               }
  810   
  811               Node.Nodes naNodes = n.getNamedAttributeNodes();
  812               int jspAttrsSize = naNodes.size() + attrsSize;
  813               Node.JspAttribute[] jspAttrs = null;
  814               if (jspAttrsSize > 0) {
  815                   jspAttrs = new Node.JspAttribute[jspAttrsSize];
  816               }
  817               Hashtable<String, Object> tagDataAttrs = new Hashtable<String, Object>(attrsSize);
  818   
  819               checkXmlAttributes(n, jspAttrs, tagDataAttrs);
  820               checkNamedAttributes(n, jspAttrs, attrsSize, tagDataAttrs);
  821   
  822               TagData tagData = new TagData(tagDataAttrs);
  823   
  824               // JSP.C1: It is a (translation time) error for an action that
  825               // has one or more variable subelements to have a TagExtraInfo
  826               // class that returns a non-null object.
  827               TagExtraInfo tei = tagInfo.getTagExtraInfo();
  828               if (tei != null && tei.getVariableInfo(tagData) != null
  829                       && tei.getVariableInfo(tagData).length > 0
  830                       && tagInfo.getTagVariableInfos().length > 0) {
  831                   err.jspError("jsp.error.non_null_tei_and_var_subelems", n
  832                           .getQName());
  833               }
  834   
  835               n.setTagData(tagData);
  836               n.setJspAttributes(jspAttrs);
  837   
  838               visitBody(n);
  839           }
  840   
  841           public void visit(Node.JspElement n) throws JasperException {
  842   
  843               Attributes attrs = n.getAttributes();
  844               if (attrs == null) {
  845                   err.jspError(n, "jsp.error.jspelement.missing.name");
  846               }
  847               int xmlAttrLen = attrs.getLength();
  848   
  849               Node.Nodes namedAttrs = n.getNamedAttributeNodes();
  850   
  851               // XML-style 'name' attribute, which is mandatory, must not be
  852               // included in JspAttribute array
  853               int jspAttrSize = xmlAttrLen - 1 + namedAttrs.size();
  854   
  855               Node.JspAttribute[] jspAttrs = new Node.JspAttribute[jspAttrSize];
  856               int jspAttrIndex = 0;
  857   
  858               // Process XML-style attributes
  859               for (int i = 0; i < xmlAttrLen; i++) {
  860                   if ("name".equals(attrs.getLocalName(i))) {
  861                       n.setNameAttribute(getJspAttribute(null, attrs.getQName(i),
  862                               attrs.getURI(i), attrs.getLocalName(i), attrs
  863                                       .getValue(i), java.lang.String.class, n,
  864                               false));
  865                   } else {
  866                       if (jspAttrIndex < jspAttrSize) {
  867                           jspAttrs[jspAttrIndex++] = getJspAttribute(null, attrs
  868                                   .getQName(i), attrs.getURI(i), attrs
  869                                   .getLocalName(i), attrs.getValue(i),
  870                                   java.lang.Object.class, n, false);
  871                       }
  872                   }
  873               }
  874               if (n.getNameAttribute() == null) {
  875                   err.jspError(n, "jsp.error.jspelement.missing.name");
  876               }
  877   
  878               // Process named attributes
  879               for (int i = 0; i < namedAttrs.size(); i++) {
  880                   Node.NamedAttribute na = (Node.NamedAttribute) namedAttrs
  881                           .getNode(i);
  882                   jspAttrs[jspAttrIndex++] = new Node.JspAttribute(na, null,
  883                           false);
  884               }
  885   
  886               n.setJspAttributes(jspAttrs);
  887   
  888               visitBody(n);
  889           }
  890   
  891           public void visit(Node.JspOutput n) throws JasperException {
  892               JspUtil.checkAttributes("jsp:output", n, jspOutputAttrs, err);
  893   
  894               if (n.getBody() != null) {
  895                   err.jspError(n, "jsp.error.jspoutput.nonemptybody");
  896               }
  897   
  898               String omitXmlDecl = n.getAttributeValue("omit-xml-declaration");
  899               String doctypeName = n.getAttributeValue("doctype-root-element");
  900               String doctypePublic = n.getAttributeValue("doctype-public");
  901               String doctypeSystem = n.getAttributeValue("doctype-system");
  902   
  903               String omitXmlDeclOld = pageInfo.getOmitXmlDecl();
  904               String doctypeNameOld = pageInfo.getDoctypeName();
  905               String doctypePublicOld = pageInfo.getDoctypePublic();
  906               String doctypeSystemOld = pageInfo.getDoctypeSystem();
  907   
  908               if (omitXmlDecl != null && omitXmlDeclOld != null
  909                       && !omitXmlDecl.equals(omitXmlDeclOld)) {
  910                   err.jspError(n, "jsp.error.jspoutput.conflict",
  911                           "omit-xml-declaration", omitXmlDeclOld, omitXmlDecl);
  912               }
  913   
  914               if (doctypeName != null && doctypeNameOld != null
  915                       && !doctypeName.equals(doctypeNameOld)) {
  916                   err.jspError(n, "jsp.error.jspoutput.conflict",
  917                           "doctype-root-element", doctypeNameOld, doctypeName);
  918               }
  919   
  920               if (doctypePublic != null && doctypePublicOld != null
  921                       && !doctypePublic.equals(doctypePublicOld)) {
  922                   err.jspError(n, "jsp.error.jspoutput.conflict",
  923                           "doctype-public", doctypePublicOld, doctypePublic);
  924               }
  925   
  926               if (doctypeSystem != null && doctypeSystemOld != null
  927                       && !doctypeSystem.equals(doctypeSystemOld)) {
  928                   err.jspError(n, "jsp.error.jspoutput.conflict",
  929                           "doctype-system", doctypeSystemOld, doctypeSystem);
  930               }
  931   
  932               if (doctypeName == null && doctypeSystem != null
  933                       || doctypeName != null && doctypeSystem == null) {
  934                   err.jspError(n, "jsp.error.jspoutput.doctypenamesystem");
  935               }
  936   
  937               if (doctypePublic != null && doctypeSystem == null) {
  938                   err.jspError(n, "jsp.error.jspoutput.doctypepulicsystem");
  939               }
  940   
  941               if (omitXmlDecl != null) {
  942                   pageInfo.setOmitXmlDecl(omitXmlDecl);
  943               }
  944               if (doctypeName != null) {
  945                   pageInfo.setDoctypeName(doctypeName);
  946               }
  947               if (doctypeSystem != null) {
  948                   pageInfo.setDoctypeSystem(doctypeSystem);
  949               }
  950               if (doctypePublic != null) {
  951                   pageInfo.setDoctypePublic(doctypePublic);
  952               }
  953           }
  954   
  955           public void visit(Node.InvokeAction n) throws JasperException {
  956   
  957               JspUtil.checkAttributes("Invoke", n, invokeAttrs, err);
  958   
  959               String scope = n.getTextAttribute("scope");
  960               JspUtil.checkScope(scope, n, err);
  961   
  962               String var = n.getTextAttribute("var");
  963               String varReader = n.getTextAttribute("varReader");
  964               if (scope != null && var == null && varReader == null) {
  965                   err.jspError(n, "jsp.error.missing_var_or_varReader");
  966               }
  967               if (var != null && varReader != null) {
  968                   err.jspError(n, "jsp.error.var_and_varReader");
  969               }
  970           }
  971   
  972           public void visit(Node.DoBodyAction n) throws JasperException {
  973   
  974               JspUtil.checkAttributes("DoBody", n, doBodyAttrs, err);
  975   
  976               String scope = n.getTextAttribute("scope");
  977               JspUtil.checkScope(scope, n, err);
  978   
  979               String var = n.getTextAttribute("var");
  980               String varReader = n.getTextAttribute("varReader");
  981               if (scope != null && var == null && varReader == null) {
  982                   err.jspError(n, "jsp.error.missing_var_or_varReader");
  983               }
  984               if (var != null && varReader != null) {
  985                   err.jspError(n, "jsp.error.var_and_varReader");
  986               }
  987           }
  988   
  989           /*
  990            * Make sure the given custom action does not have any invalid
  991            * attributes.
  992            * 
  993            * A custom action and its declared attributes always belong to the same
  994            * namespace, which is identified by the prefix name of the custom tag
  995            * invocation. For example, in this invocation:
  996            * 
  997            * <my:test a="1" b="2" c="3"/>, the action
  998            * 
  999            * "test" and its attributes "a", "b", and "c" all belong to the
 1000            * namespace identified by the prefix "my". The above invocation would
 1001            * be equivalent to:
 1002            * 
 1003            * <my:test my:a="1" my:b="2" my:c="3"/>
 1004            * 
 1005            * An action attribute may have a prefix different from that of the
 1006            * action invocation only if the underlying tag handler supports dynamic
 1007            * attributes, in which case the attribute with the different prefix is
 1008            * considered a dynamic attribute.
 1009            */
 1010           private void checkXmlAttributes(Node.CustomTag n,
 1011                   Node.JspAttribute[] jspAttrs, Hashtable<String, Object> tagDataAttrs)
 1012                   throws JasperException {
 1013   
 1014               TagInfo tagInfo = n.getTagInfo();
 1015               if (tagInfo == null) {
 1016                   err.jspError(n, "jsp.error.missing.tagInfo", n.getQName());
 1017               }
 1018               TagAttributeInfo[] tldAttrs = tagInfo.getAttributes();
 1019               Attributes attrs = n.getAttributes();
 1020   
 1021               boolean checkDeferred = !pageInfo.isDeferredSyntaxAllowedAsLiteral()
 1022                   && !(tagInfo.getTagLibrary().getRequiredVersion().equals("2.0")
 1023                           || tagInfo.getTagLibrary().getRequiredVersion().equals("1.2"));
 1024   
 1025               for (int i = 0; attrs != null && i < attrs.getLength(); i++) {
 1026                   boolean found = false;
 1027                   
 1028                   boolean runtimeExpression = ((n.getRoot().isXmlSyntax() && attrs.getValue(i).startsWith("%="))
 1029                           || (!n.getRoot().isXmlSyntax() && attrs.getValue(i).startsWith("<%=")));
 1030                   boolean elExpression = false;
 1031                   boolean deferred = false;
 1032                   boolean deferredValueIsLiteral = false;
 1033   
 1034                   ELNode.Nodes el = null;
 1035                   if (!runtimeExpression) {
 1036                       el = ELParser.parse(attrs.getValue(i));
 1037                       Iterator<ELNode> nodes = el.iterator();
 1038                       while (nodes.hasNext()) {
 1039                           ELNode node = nodes.next();
 1040                           if (node instanceof ELNode.Root) {
 1041                               if (((ELNode.Root) node).getType() == '$') {
 1042                                   elExpression = true;
 1043                               } else if (checkDeferred && ((ELNode.Root) node).getType() == '#') {
 1044                                   elExpression = true;
 1045                                   deferred = true;
 1046                                   if (pageInfo.isELIgnored()) {
 1047                                       deferredValueIsLiteral = true;
 1048                                   }
 1049                               }
 1050                           }
 1051                       }
 1052                   }
 1053   
 1054                   boolean expression = runtimeExpression 
 1055                       || (elExpression  && (!pageInfo.isELIgnored() || (!"true".equalsIgnoreCase(pageInfo.getIsELIgnored()) && checkDeferred && deferred)));
 1056                   
 1057                   for (int j = 0; tldAttrs != null && j < tldAttrs.length; j++) {
 1058                       if (attrs.getLocalName(i).equals(tldAttrs[j].getName())
 1059                               && (attrs.getURI(i) == null
 1060                                       || attrs.getURI(i).length() == 0 || attrs
 1061                                       .getURI(i).equals(n.getURI()))) {
 1062                           
 1063                           if (tldAttrs[j].canBeRequestTime()
 1064                                   || tldAttrs[j].isDeferredMethod() || tldAttrs[j].isDeferredValue()) { // JSP 2.1
 1065                               
 1066                               if (!expression) {
 1067                                   
 1068                                   if (deferredValueIsLiteral && !pageInfo.isDeferredSyntaxAllowedAsLiteral()) {
 1069                                       err.jspError(n, "jsp.error.attribute.custom.non_rt_with_expr",
 1070                                               tldAttrs[j].getName());
 1071                                   }
 1072                                   
 1073                                   String expectedType = null;
 1074                                   if (tldAttrs[j].isDeferredMethod()) {
 1075                                       // The String litteral must be castable to what is declared as type
 1076                                       // for the attribute
 1077                                       String m = tldAttrs[j].getMethodSignature();
 1078                                       if (m != null) {
 1079                                           int rti = m.trim().indexOf(' ');
 1080                                           if (rti > 0) {
 1081                                               expectedType = m.substring(0, rti).trim();
 1082                                           }
 1083                                       } else {
 1084                                           expectedType = "java.lang.Object";
 1085                                       }
 1086                                   }
 1087                                   if (tldAttrs[j].isDeferredValue()) {
 1088                                       // The String litteral must be castable to what is declared as type
 1089                                       // for the attribute
 1090                                       expectedType = tldAttrs[j].getExpectedTypeName();
 1091                                   }
 1092                                   if (expectedType != null) {
 1093                                       Class expectedClass = String.class;
 1094                                       try {
 1095                                           expectedClass = JspUtil.toClass(expectedType, loader);
 1096                                       } catch (ClassNotFoundException e) {
 1097                                           err.jspError
 1098                                               (n, "jsp.error.unknown_attribute_type",
 1099                                                tldAttrs[j].getName(), expectedType);
 1100                                       }
 1101                                       // Check casting
 1102                                       try {
 1103                                           ELSupport.checkType(attrs.getValue(i), expectedClass);
 1104                                       } catch (Exception e) {
 1105                                           err.jspError
 1106                                               (n, "jsp.error.coerce_to_type",
 1107                                                tldAttrs[j].getName(), expectedType, attrs.getValue(i));
 1108                                       }
 1109                                   }
 1110   
 1111                                   jspAttrs[i] = new Node.JspAttribute(tldAttrs[j],
 1112                                           attrs.getQName(i), attrs.getURI(i), attrs
 1113                                                   .getLocalName(i),
 1114                                           attrs.getValue(i), false, null, false);
 1115                               } else {
 1116                                   
 1117                                   if (deferred && !tldAttrs[j].isDeferredMethod() && !tldAttrs[j].isDeferredValue()) {
 1118                                       // No deferred expressions allowed for this attribute
 1119                                       err.jspError(n, "jsp.error.attribute.custom.non_rt_with_expr",
 1120                                               tldAttrs[j].getName());
 1121                                   }
 1122                                   if (!deferred && !tldAttrs[j].canBeRequestTime()) {
 1123                                       // Only deferred expressions are allowed for this attribute
 1124                                       err.jspError(n, "jsp.error.attribute.custom.non_rt_with_expr",
 1125                                               tldAttrs[j].getName());
 1126                                   }
 1127                                   
 1128                                   Class expectedType = String.class;
 1129                                   try {
 1130                                       String typeStr = tldAttrs[j].getTypeName();
 1131                                       if (tldAttrs[j].isFragment()) {
 1132                                           expectedType = JspFragment.class;
 1133                                       } else if (typeStr != null) {
 1134                                           expectedType = JspUtil.toClass(typeStr,
 1135                                                   loader);
 1136                                       }
 1137                                       if (elExpression) {
 1138                                           // El expression
 1139                                           validateFunctions(el, n);
 1140                                           jspAttrs[i] = new Node.JspAttribute(tldAttrs[j],
 1141                                                   attrs.getQName(i), attrs.getURI(i), 
 1142                                                   attrs.getLocalName(i),
 1143                                                   attrs.getValue(i), false, el, false);
 1144                                           ELContextImpl ctx = new ELContextImpl();
 1145                                           ctx.setFunctionMapper(getFunctionMapper(el));
 1146                                           try {
 1147                                               jspAttrs[i].validateEL(this.pageInfo.getExpressionFactory(), ctx);
 1148                                           } catch (ELException e) {
 1149                                               this.err.jspError(n.getStart(),
 1150                                                       "jsp.error.invalid.expression", 
 1151                                                       attrs.getValue(i), e.toString());
 1152                                           }
 1153                                       } else {
 1154                                           // Runtime expression
 1155                                           jspAttrs[i] = getJspAttribute(tldAttrs[j],
 1156                                                   attrs.getQName(i), attrs.getURI(i),
 1157                                                   attrs.getLocalName(i), attrs
 1158                                                   .getValue(i), expectedType, n,
 1159                                                   false);
 1160                                       }
 1161                                   } catch (ClassNotFoundException e) {
 1162                                       err.jspError
 1163                                           (n, "jsp.error.unknown_attribute_type",
 1164                                            tldAttrs[j].getName(), tldAttrs[j].getTypeName());
 1165                                   }
 1166                               }
 1167                               
 1168                           } else {
 1169                               // Attribute does not accept any expressions.
 1170                               // Make sure its value does not contain any.
 1171                               if (expression) {
 1172                                   err.jspError(n, "jsp.error.attribute.custom.non_rt_with_expr",
 1173                                                   tldAttrs[j].getName());
 1174                               }
 1175                               jspAttrs[i] = new Node.JspAttribute(tldAttrs[j],
 1176                                       attrs.getQName(i), attrs.getURI(i), attrs
 1177                                               .getLocalName(i),
 1178                                       attrs.getValue(i), false, null, false);
 1179                           }
 1180                           if (expression) {
 1181                               tagDataAttrs.put(attrs.getQName(i),
 1182                                       TagData.REQUEST_TIME_VALUE);
 1183                           } else {
 1184                               tagDataAttrs.put(attrs.getQName(i), attrs
 1185                                       .getValue(i));
 1186                           }
 1187                           found = true;
 1188                           break;
 1189                       }
 1190                   }
 1191                   if (!found) {
 1192                       if (tagInfo.hasDynamicAttributes()) {
 1193                           jspAttrs[i] = getJspAttribute(null, attrs.getQName(i),
 1194                                   attrs.getURI(i), attrs.getLocalName(i), attrs
 1195                                           .getValue(i), java.lang.Object.class,
 1196                                   n, true);
 1197                       } else {
 1198                           err.jspError(n, "jsp.error.bad_attribute", attrs
 1199                                   .getQName(i), n.getLocalName());
 1200                       }
 1201                   }
 1202               }
 1203           }
 1204   
 1205           /*
 1206            * Make sure the given custom action does not have any invalid named
 1207            * attributes
 1208            */
 1209           private void checkNamedAttributes(Node.CustomTag n,
 1210                   Node.JspAttribute[] jspAttrs, int start, 
 1211                   Hashtable<String, Object> tagDataAttrs)
 1212                   throws JasperException {
 1213   
 1214               TagInfo tagInfo = n.getTagInfo();
 1215               if (tagInfo == null) {
 1216                   err.jspError(n, "jsp.error.missing.tagInfo", n.getQName());
 1217               }
 1218               TagAttributeInfo[] tldAttrs = tagInfo.getAttributes();
 1219               Node.Nodes naNodes = n.getNamedAttributeNodes();
 1220   
 1221               for (int i = 0; i < naNodes.size(); i++) {
 1222                   Node.NamedAttribute na = (Node.NamedAttribute) naNodes
 1223                           .getNode(i);
 1224                   boolean found = false;
 1225                   for (int j = 0; j < tldAttrs.length; j++) {
 1226                       /*
 1227                        * See above comment about namespace matches. For named
 1228                        * attributes, we use the prefix instead of URI as the match
 1229                        * criterion, because in the case of a JSP document, we'd
 1230                        * have to keep track of which namespaces are in scope when
 1231                        * parsing a named attribute, in order to determine the URI
 1232                        * that the prefix of the named attribute's name matches to.
 1233                        */
 1234                       String attrPrefix = na.getPrefix();
 1235                       if (na.getLocalName().equals(tldAttrs[j].getName())
 1236                               && (attrPrefix == null || attrPrefix.length() == 0 || attrPrefix
 1237                                       .equals(n.getPrefix()))) {
 1238                           jspAttrs[start + i] = new Node.JspAttribute(na,
 1239                                   tldAttrs[j], false);
 1240                           NamedAttributeVisitor nav = null;
 1241                           if (na.getBody() != null) {
 1242                               nav = new NamedAttributeVisitor();
 1243                               na.getBody().visit(nav);
 1244                           }
 1245                           if (nav != null && nav.hasDynamicContent()) {
 1246                               tagDataAttrs.put(na.getName(),
 1247                                       TagData.REQUEST_TIME_VALUE);
 1248                           } else {
 1249                               tagDataAttrs.put(na.getName(), na.getText());
 1250                           }
 1251                           found = true;
 1252                           break;
 1253                       }
 1254                   }
 1255                   if (!found) {
 1256                       if (tagInfo.hasDynamicAttributes()) {
 1257                           jspAttrs[start + i] = new Node.JspAttribute(na, null,
 1258                                   true);
 1259                       } else {
 1260                           err.jspError(n, "jsp.error.bad_attribute",
 1261                                   na.getName(), n.getLocalName());
 1262                       }
 1263                   }
 1264               }
 1265           }
 1266   
 1267           /**
 1268            * Preprocess attributes that can be expressions. Expression delimiters
 1269            * are stripped.
 1270            * <p>
 1271            * If value is null, checks if there are any NamedAttribute subelements
 1272            * in the tree node, and if so, constructs a JspAttribute out of a child
 1273            * NamedAttribute node.
 1274            */
 1275           private Node.JspAttribute getJspAttribute(TagAttributeInfo tai,
 1276                   String qName, String uri, String localName, String value,
 1277                   Class expectedType, Node n, boolean dynamic)
 1278                   throws JasperException {
 1279   
 1280               Node.JspAttribute result = null;
 1281   
 1282               // XXX Is it an error to see "%=foo%" in non-Xml page?
 1283               // (We won't see "<%=foo%> in xml page because '<' is not a
 1284               // valid attribute value in xml).
 1285   
 1286               if (value != null) {
 1287                   if (n.getRoot().isXmlSyntax() && value.startsWith("%=")) {
 1288                       result = new Node.JspAttribute(tai, qName, uri, localName,
 1289                               value.substring(2, value.length() - 1), true, null,
 1290                               dynamic);
 1291                   } else if (!n.getRoot().isXmlSyntax()
 1292                           && value.startsWith("<%=")) {
 1293                       result = new Node.JspAttribute(tai, qName, uri, localName,
 1294                               value.substring(3, value.length() - 2), true, null,
 1295                               dynamic);
 1296                   } else {
 1297                       // The attribute can contain expressions but is not a
 1298                       // scriptlet expression; thus, we want to run it through
 1299                       // the expression interpreter
 1300   
 1301                       // validate expression syntax if string contains
 1302                       // expression(s)
 1303                       ELNode.Nodes el = ELParser.parse(value);
 1304                       
 1305                       boolean deferred = false;
 1306                       Iterator<ELNode> nodes = el.iterator();
 1307                       while (nodes.hasNext()) {
 1308                           ELNode node = nodes.next();
 1309                           if (node instanceof ELNode.Root) {
 1310                               if (((ELNode.Root) node).getType() == '#') {
 1311                                   deferred = true;
 1312                               }
 1313                           }
 1314                       }
 1315   
 1316                       if (el.containsEL() && !pageInfo.isELIgnored()
 1317                               && ((!pageInfo.isDeferredSyntaxAllowedAsLiteral() && deferred)
 1318                                       || !deferred)) {
 1319   
 1320                           validateFunctions(el, n);
 1321   
 1322                           result = new Node.JspAttribute(tai, qName, uri,
 1323                                   localName, value, false, el, dynamic);
 1324   
 1325                           ELContextImpl ctx = new ELContextImpl();
 1326                           ctx.setFunctionMapper(getFunctionMapper(el));
 1327   
 1328                           try {
 1329                               result.validateEL(this.pageInfo
 1330                                       .getExpressionFactory(), ctx);
 1331                           } catch (ELException e) {
 1332                               this.err.jspError(n.getStart(),
 1333                                       "jsp.error.invalid.expression", value, e
 1334                                               .toString());
 1335                           }
 1336   
 1337                       } else {
 1338                           value = value.replace(Constants.ESC, '$');
 1339                           result = new Node.JspAttribute(tai, qName, uri,
 1340                                   localName, value, false, null, dynamic);
 1341                       }
 1342                   }
 1343               } else {
 1344                   // Value is null. Check for any NamedAttribute subnodes
 1345                   // that might contain the value for this attribute.
 1346                   // Otherwise, the attribute wasn't found so we return null.
 1347   
 1348                   Node.NamedAttribute namedAttributeNode = n
 1349                           .getNamedAttributeNode(qName);
 1350                   if (namedAttributeNode != null) {
 1351                       result = new Node.JspAttribute(namedAttributeNode, tai,
 1352                               dynamic);
 1353                   }
 1354               }
 1355   
 1356               return result;
 1357           }
 1358   
 1359           /*
 1360            * Return an empty StringBuffer [not thread-safe]
 1361            */
 1362           private StringBuffer getBuffer() {
 1363               this.buf.setLength(0);
 1364               return this.buf;
 1365           }
 1366   
 1367           /*
 1368            * Checks to see if the given attribute value represents a runtime or EL
 1369            * expression.
 1370            */
 1371           private boolean isExpression(Node n, String value, boolean checkDeferred) {
 1372               
 1373               boolean runtimeExpression = ((n.getRoot().isXmlSyntax() && value.startsWith("%="))
 1374                       || (!n.getRoot().isXmlSyntax() && value.startsWith("<%=")));
 1375               boolean elExpression = false;
 1376   
 1377               if (!runtimeExpression && !pageInfo.isELIgnored()) {
 1378                   Iterator<ELNode> nodes = ELParser.parse(value).iterator();
 1379                   while (nodes.hasNext()) {
 1380                       ELNode node = nodes.next();
 1381                       if (node instanceof ELNode.Root) {
 1382                           if (((ELNode.Root) node).getType() == '$') {
 1383                               elExpression = true;
 1384                           } else if (checkDeferred && !pageInfo.isDeferredSyntaxAllowedAsLiteral() 
 1385                                   && ((ELNode.Root) node).getType() == '#') {
 1386                               elExpression = true;
 1387                           }
 1388                       }
 1389                   }
 1390               }
 1391   
 1392               return runtimeExpression || elExpression;
 1393   
 1394           }
 1395   
 1396           /*
 1397            * Throws exception if the value of the attribute with the given name in
 1398            * the given node is given as an RT or EL expression, but the spec
 1399            * requires a static value.
 1400            */
 1401           private void throwErrorIfExpression(Node n, String attrName,
 1402                   String actionName) throws JasperException {
 1403               if (n.getAttributes() != null
 1404                       && n.getAttributes().getValue(attrName) != null
 1405                       && isExpression(n, n.getAttributes().getValue(attrName), true)) {
 1406                   err.jspError(n,
 1407                           "jsp.error.attribute.standard.non_rt_with_expr",
 1408                           attrName, actionName);
 1409               }
 1410           }
 1411   
 1412           private static class NamedAttributeVisitor extends Node.Visitor {
 1413               private boolean hasDynamicContent;
 1414   
 1415               public void doVisit(Node n) throws JasperException {
 1416                   if (!(n instanceof Node.JspText)
 1417                           && !(n instanceof Node.TemplateText)) {
 1418                       hasDynamicContent = true;
 1419                   }
 1420                   visitBody(n);
 1421               }
 1422   
 1423               public boolean hasDynamicContent() {
 1424                   return hasDynamicContent;
 1425               }
 1426           }
 1427   
 1428           private String findUri(String prefix, Node n) {
 1429   
 1430               for (Node p = n; p != null; p = p.getParent()) {
 1431                   Attributes attrs = p.getTaglibAttributes();
 1432                   if (attrs == null) {
 1433                       continue;
 1434                   }
 1435                   for (int i = 0; i < attrs.getLength(); i++) {
 1436                       String name = attrs.getQName(i);
 1437                       int k = name.indexOf(':');
 1438                       if (prefix == null && k < 0) {
 1439                           // prefix not specified and a default ns found
 1440                           return attrs.getValue(i);
 1441                       }
 1442                       if (prefix != null && k >= 0
 1443                               && prefix.equals(name.substring(k + 1))) {
 1444                           return attrs.getValue(i);
 1445                       }
 1446                   }
 1447               }
 1448               return null;
 1449           }
 1450   
 1451           /**
 1452            * Validate functions in EL expressions
 1453            */
 1454           private void validateFunctions(ELNode.Nodes el, Node n)
 1455                   throws JasperException {
 1456   
 1457               class FVVisitor extends ELNode.Visitor {
 1458   
 1459                   Node n;
 1460   
 1461                   FVVisitor(Node n) {
 1462                       this.n = n;
 1463                   }
 1464   
 1465                   public void visit(ELNode.Function func) throws JasperException {
 1466                       String prefix = func.getPrefix();
 1467                       String function = func.getName();
 1468                       String uri = null;
 1469   
 1470                       if (n.getRoot().isXmlSyntax()) {
 1471                           uri = findUri(prefix, n);
 1472                       } else if (prefix != null) {
 1473                           uri = pageInfo.getURI(prefix);
 1474                       }
 1475   
 1476                       if (uri == null) {
 1477                           if (prefix == null) {
 1478                               err.jspError(n, "jsp.error.noFunctionPrefix",
 1479                                       function);
 1480                           } else {
 1481                               err
 1482                                       .jspError(
 1483                                               n,
 1484                                               "jsp.error.attribute.invalidPrefix",
 1485                                               prefix);
 1486                           }
 1487                       }
 1488                       TagLibraryInfo taglib = pageInfo.getTaglib(uri);
 1489                       FunctionInfo funcInfo = null;
 1490                       if (taglib != null) {
 1491                           funcInfo = taglib.getFunction(function);
 1492                       }
 1493                       if (funcInfo == null) {
 1494                           err.jspError(n, "jsp.error.noFunction", function);
 1495                       }
 1496                       // Skip TLD function uniqueness check. Done by Schema ?
 1497                       func.setUri(uri);
 1498                       func.setFunctionInfo(funcInfo);
 1499                       processSignature(func);
 1500                   }
 1501               }
 1502   
 1503               el.visit(new FVVisitor(n));
 1504           }
 1505   
 1506           private void prepareExpression(ELNode.Nodes el, Node n, String expr)
 1507                   throws JasperException {
 1508               validateFunctions(el, n);
 1509   
 1510               // test it out
 1511               ELContextImpl ctx = new ELContextImpl();
 1512               ctx.setFunctionMapper(this.getFunctionMapper(el));
 1513               ExpressionFactory ef = this.pageInfo.getExpressionFactory();
 1514               try {
 1515                   ef.createValueExpression(ctx, expr, Object.class);
 1516               } catch (ELException e) {
 1517   
 1518               }
 1519           }
 1520   
 1521           private void processSignature(ELNode.Function func)
 1522                   throws JasperException {
 1523               func.setMethodName(getMethod(func));
 1524               func.setParameters(getParameters(func));
 1525           }
 1526   
 1527           /**
 1528            * Get the method name from the signature.
 1529            */
 1530           private String getMethod(ELNode.Function func) throws JasperException {
 1531               FunctionInfo funcInfo = func.getFunctionInfo();
 1532               String signature = funcInfo.getFunctionSignature();
 1533   
 1534               int start = signature.indexOf(' ');
 1535               if (start < 0) {
 1536                   err.jspError("jsp.error.tld.fn.invalid.signature", func
 1537                           .getPrefix(), func.getName());
 1538               }
 1539               int end = signature.indexOf('(');
 1540               if (end < 0) {
 1541                   err.jspError(
 1542                           "jsp.error.tld.fn.invalid.signature.parenexpected",
 1543                           func.getPrefix(), func.getName());
 1544               }
 1545               return signature.substring(start + 1, end).trim();
 1546           }
 1547   
 1548           /**
 1549            * Get the parameters types from the function signature.
 1550            * 
 1551            * @return An array of parameter class names
 1552            */
 1553           private String[] getParameters(ELNode.Function func)
 1554                   throws JasperException {
 1555               FunctionInfo funcInfo = func.getFunctionInfo();
 1556               String signature = funcInfo.getFunctionSignature();
 1557               ArrayList<String> params = new ArrayList<String>();
 1558               // Signature is of the form
 1559               // <return-type> S <method-name S? '('
 1560               // < <arg-type> ( ',' <arg-type> )* )? ')'
 1561               int start = signature.indexOf('(') + 1;
 1562               boolean lastArg = false;
 1563               while (true) {
 1564                   int p = signature.indexOf(',', start);
 1565                   if (p < 0) {
 1566                       p = signature.indexOf(')', start);
 1567                       if (p < 0) {
 1568                           err.jspError("jsp.error.tld.fn.invalid.signature", func
 1569                                   .getPrefix(), func.getName());
 1570                       }
 1571                       lastArg = true;
 1572                   }
 1573                   String arg = signature.substring(start, p).trim();
 1574                   if (!"".equals(arg)) {
 1575                       params.add(arg);
 1576                   }
 1577                   if (lastArg) {
 1578                       break;
 1579                   }
 1580                   start = p + 1;
 1581               }
 1582               return (String[]) params.toArray(new String[params.size()]);
 1583           }
 1584   
 1585           private FunctionMapper getFunctionMapper(ELNode.Nodes el)
 1586                   throws JasperException {
 1587   
 1588               class ValidateFunctionMapper extends FunctionMapper {
 1589   
 1590                   private HashMap<String, Method> fnmap = new HashMap<String, Method>();
 1591   
 1592                   public void mapFunction(String fnQName, Method method) {
 1593                       fnmap.put(fnQName, method);
 1594                   }
 1595   
 1596                   public Method resolveFunction(String prefix, String localName) {
 1597                       return this.fnmap.get(prefix + ":" + localName);
 1598                   }
 1599               }
 1600   
 1601               class MapperELVisitor extends ELNode.Visitor {
 1602                   ValidateFunctionMapper fmapper;
 1603   
 1604                   MapperELVisitor(ValidateFunctionMapper fmapper) {
 1605                       this.fmapper = fmapper;
 1606                   }
 1607   
 1608                   public void visit(ELNode.Function n) throws JasperException {
 1609   
 1610                       Class c = null;
 1611                       Method method = null;
 1612                       try {
 1613                           c = loader.loadClass(n.getFunctionInfo()
 1614                                   .getFunctionClass());
 1615                       } catch (ClassNotFoundException e) {
 1616                           err.jspError("jsp.error.function.classnotfound", n
 1617                                   .getFunctionInfo().getFunctionClass(), n
 1618                                   .getPrefix()
 1619                                   + ':' + n.getName(), e.getMessage());
 1620                       }
 1621                       String paramTypes[] = n.getParameters();
 1622                       int size = paramTypes.length;
 1623                       Class params[] = new Class[size];
 1624                       int i = 0;
 1625                       try {
 1626                           for (i = 0; i < size; i++) {
 1627                               params[i] = JspUtil.toClass(paramTypes[i], loader);
 1628                           }
 1629                           method = c.getDeclaredMethod(n.getMethodName(), params);
 1630                       } catch (ClassNotFoundException e) {
 1631                           err.jspError("jsp.error.signature.classnotfound",
 1632                                   paramTypes[i], n.getPrefix() + ':'
 1633                                           + n.getName(), e.getMessage());
 1634                       } catch (NoSuchMethodException e) {
 1635                           err.jspError("jsp.error.noFunctionMethod", n
 1636                                   .getMethodName(), n.getName(), c.getName());
 1637                       }
 1638                       fmapper.mapFunction(n.getPrefix() + ':' + n.getName(),
 1639                               method);
 1640                   }
 1641               }
 1642   
 1643               ValidateFunctionMapper fmapper = new ValidateFunctionMapper();
 1644               el.visit(new MapperELVisitor(fmapper));
 1645               return fmapper;
 1646           }
 1647       } // End of ValidateVisitor
 1648   
 1649       /**
 1650        * A visitor for validating TagExtraInfo classes of all tags
 1651        */
 1652       static class TagExtraInfoVisitor extends Node.Visitor {
 1653   
 1654           private ErrorDispatcher err;
 1655   
 1656           /*
 1657            * Constructor
 1658            */
 1659           TagExtraInfoVisitor(Compiler compiler) {
 1660               this.err = compiler.getErrorDispatcher();
 1661           }
 1662   
 1663           public void visit(Node.CustomTag n) throws JasperException {
 1664               TagInfo tagInfo = n.getTagInfo();
 1665               if (tagInfo == null) {
 1666                   err.jspError(n, "jsp.error.missing.tagInfo", n.getQName());
 1667               }
 1668   
 1669               ValidationMessage[] errors = tagInfo.validate(n.getTagData());
 1670               if (errors != null && errors.length != 0) {
 1671                   StringBuffer errMsg = new StringBuffer();
 1672                   errMsg.append("<h3>");
 1673                   errMsg.append(Localizer.getMessage(
 1674                           "jsp.error.tei.invalid.attributes", n.getQName()));
 1675                   errMsg.append("</h3>");
 1676                   for (int i = 0; i < errors.length; i++) {
 1677                       errMsg.append("<p>");
 1678                       if (errors[i].getId() != null) {
 1679                           errMsg.append(errors[i].getId());
 1680                           errMsg.append(": ");
 1681                       }
 1682                       errMsg.append(errors[i].getMessage());
 1683                       errMsg.append("</p>");
 1684                   }
 1685   
 1686                   err.jspError(n, errMsg.toString());
 1687               }
 1688   
 1689               visitBody(n);
 1690           }
 1691       }
 1692   
 1693       public static void validate(Compiler compiler, Node.Nodes page)
 1694               throws JasperException {
 1695   
 1696           /*
 1697            * Visit the page/tag directives first, as they are global to the page
 1698            * and are position independent.
 1699            */
 1700           page.visit(new DirectiveVisitor(compiler));
 1701   
 1702           // Determine the default output content type
 1703           PageInfo pageInfo = compiler.getPageInfo();
 1704           String contentType = pageInfo.getContentType();
 1705   
 1706           if (contentType == null || contentType.indexOf("charset=") < 0) {
 1707               boolean isXml = page.getRoot().isXmlSyntax();
 1708               String defaultType;
 1709               if (contentType == null) {
 1710                   defaultType = isXml ? "text/xml" : "text/html";
 1711               } else {
 1712                   defaultType = contentType;
 1713               }
 1714   
 1715               String charset = null;
 1716               if (isXml) {
 1717                   charset = "UTF-8";
 1718               } else {
 1719                   if (!page.getRoot().isDefaultPageEncoding()) {
 1720                       charset = page.getRoot().getPageEncoding();
 1721                   }
 1722               }
 1723   
 1724               if (charset != null) {
 1725                   pageInfo.setContentType(defaultType + ";charset=" + charset);
 1726               } else {
 1727                   pageInfo.setContentType(defaultType);
 1728               }
 1729           }
 1730   
 1731           /*
 1732            * Validate all other nodes. This validation step includes checking a
 1733            * custom tag's mandatory and optional attributes against information in
 1734            * the TLD (first validation step for custom tags according to
 1735            * JSP.10.5).
 1736            */
 1737           page.visit(new ValidateVisitor(compiler));
 1738   
 1739           /*
 1740            * Invoke TagLibraryValidator classes of all imported tags (second
 1741            * validation step for custom tags according to JSP.10.5).
 1742            */
 1743           validateXmlView(new PageDataImpl(page, compiler), compiler);
 1744   
 1745           /*
 1746            * Invoke TagExtraInfo method isValid() for all imported tags (third
 1747            * validation step for custom tags according to JSP.10.5).
 1748            */
 1749           page.visit(new TagExtraInfoVisitor(compiler));
 1750   
 1751       }
 1752   
 1753       // *********************************************************************
 1754       // Private (utility) methods
 1755   
 1756       /**
 1757        * Validate XML view against the TagLibraryValidator classes of all imported
 1758        * tag libraries.
 1759        */
 1760       private static void validateXmlView(PageData xmlView, Compiler compiler)
 1761               throws JasperException {
 1762   
 1763           StringBuffer errMsg = null;
 1764           ErrorDispatcher errDisp = compiler.getErrorDispatcher();
 1765   
 1766           for (Iterator iter = compiler.getPageInfo().getTaglibs().iterator(); iter
 1767                   .hasNext();) {
 1768   
 1769               Object o = iter.next();
 1770               if (!(o instanceof TagLibraryInfoImpl))
 1771                   continue;
 1772               TagLibraryInfoImpl tli = (TagLibraryInfoImpl) o;
 1773   
 1774               ValidationMessage[] errors = tli.validate(xmlView);
 1775               if ((errors != null) && (errors.length != 0)) {
 1776                   if (errMsg == null) {
 1777                       errMsg = new StringBuffer();
 1778                   }
 1779                   errMsg.append("<h3>");
 1780                   errMsg.append(Localizer.getMessage(
 1781                           "jsp.error.tlv.invalid.page", tli.getShortName(),
 1782                           compiler.getPageInfo().getJspFile()));
 1783                   errMsg.append("</h3>");
 1784                   for (int i = 0; i < errors.length; i++) {
 1785                       if (errors[i] != null) {
 1786                           errMsg.append("<p>");
 1787                           errMsg.append(errors[i].getId());
 1788                           errMsg.append(": ");
 1789                           errMsg.append(errors[i].getMessage());
 1790                           errMsg.append("</p>");
 1791                       }
 1792                   }
 1793               }
 1794           }
 1795   
 1796           if (errMsg != null) {
 1797               errDisp.jspError(errMsg.toString());
 1798           }
 1799       }
 1800   }

Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » jasper » compiler » [javadoc | source]