Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    * Licensed to the Apache Software Foundation (ASF) under one or more
    * contributor license agreements.  See the NOTICE file distributed with
    * this work for additional information regarding copyright ownership.
    * The ASF licenses this file to You under the Apache License, Version 2.0
    * (the "License"); you may not use this file except in compliance with
    * the License.  You may obtain a copy of the License at
    * 
    *      http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.jasper.compiler;
  
  import static org.jboss.web.JasperMessages.MESSAGES;
  
  import java.util.HashMap;
  import java.util.Locale;
  
  
Performs validation on the page elements. Attributes are checked for mandatory presence, entry value validity, and consistency. As a side effect, some page global value (such as those from page direcitves) are stored, for later use.

Author(s):
Kin-man Chung
Jan Luehe
Shawn Bayern
Mark Roth
  
  class Validator {

    
A visitor to validate and extract page directive info
  
      static class DirectiveVisitor extends Node.Visitor {
  
          private PageInfo pageInfo;
  
          private ErrorDispatcher err;
  
          private static final JspUtil.ValidAttribute[] pageDirectiveAttrs = {
              new JspUtil.ValidAttribute("language"),
              new JspUtil.ValidAttribute("extends"),
              new JspUtil.ValidAttribute("import"),
              new JspUtil.ValidAttribute("session"),
              new JspUtil.ValidAttribute("buffer"),
              new JspUtil.ValidAttribute("autoFlush"),
              new JspUtil.ValidAttribute("isThreadSafe"),
              new JspUtil.ValidAttribute("info"),
              new JspUtil.ValidAttribute("errorPage"),
              new JspUtil.ValidAttribute("isErrorPage"),
              new JspUtil.ValidAttribute("contentType"),
              new JspUtil.ValidAttribute("pageEncoding"),
              new JspUtil.ValidAttribute("isELIgnored"),
              new JspUtil.ValidAttribute("deferredSyntaxAllowedAsLiteral"),
              new JspUtil.ValidAttribute("trimDirectiveWhitespaces")
          };
  
          private boolean pageEncodingSeen = false;
  
          /*
           * Constructor
           */
          DirectiveVisitor(Compiler compilerthrows JasperException {
              this. = compiler.getPageInfo();
              this. = compiler.getErrorDispatcher();
          }
  
          public void visit(Node.IncludeDirective nthrows JasperException {
              // Since pageDirectiveSeen flag only applies to the Current page
             // save it here and restore it after the file is included.
             boolean pageEncodingSeenSave = ;
              = false;
             visitBody(n);
              = pageEncodingSeenSave;
         }
 
         public void visit(Node.PageDirective nthrows JasperException {
 
                     );
 
             // JSP.2.10.1
             Attributes attrs = n.getAttributes();
             for (int i = 0; attrs != null && i < attrs.getLength(); i++) {
                 String attr = attrs.getQName(i);
                 String value = attrs.getValue(i);
 
                 if ("language".equals(attr)) {
                     if (.getLanguage(false) == null) {
                         .setLanguage(valuentrue);
                     } else if (!.getLanguage(false).equals(value)) {
                         .jspError(n.getStart(), .invalidConflictingPageDirectiveAttribute
                                 (attr.getLanguage(false), value));
                     }
                 } else if ("extends".equals(attr)) {
                     if (.getExtends(false) == null) {
                         .setExtends(value);
                     } else if (!.getExtends(false).equals(value)) {
                         .jspError(n.getStart(), .invalidConflictingPageDirectiveAttribute
                                 (attr.getExtends(false), value));
                     }
                 } else if ("contentType".equals(attr)) {
                     if (.getContentType() == null) {
                         .setContentType(value);
                     } else if (!.getContentType().equals(value)) {
                         .jspError(n.getStart(), .invalidConflictingPageDirectiveAttribute
                                 (attr.getContentType(), value));
                     }
                 } else if ("session".equals(attr)) {
                     if (.getSession() == null) {
                         .setSession(valuen);
                     } else if (!.getSession().equals(value)) {
                         .jspError(n.getStart(), .invalidConflictingPageDirectiveAttribute
                                 (attr.getSession(), value));
                     }
                 } else if ("buffer".equals(attr)) {
                     if (.getBufferValue() == null) {
                         .setBufferValue(valuen);
                     } else if (!.getBufferValue().equals(value)) {
                         .jspError(n.getStart(), .invalidConflictingPageDirectiveAttribute
                                 (attr.getBufferValue(), value));
                     }
                 } else if ("autoFlush".equals(attr)) {
                     if (.getAutoFlush() == null) {
                         .setAutoFlush(valuen);
                     } else if (!.getAutoFlush().equals(value)) {
                         .jspError(n.getStart(), .invalidConflictingPageDirectiveAttribute
                                 (attr.getAutoFlush(), value));
                     }
                 } else if ("isThreadSafe".equals(attr)) {
                     if (.getIsThreadSafe() == null) {
                         .setIsThreadSafe(valuen);
                     } else if (!.getIsThreadSafe().equals(value)) {
                         .jspError(n.getStart(), .invalidConflictingPageDirectiveAttribute
                                 (attr.getIsThreadSafe(), value));
                     }
                 } else if ("isELIgnored".equals(attr)) {
                     if (.getIsELIgnored() == null) {
                         .setIsELIgnored(valuentrue);
                     } else if (!.getIsELIgnored().equals(value)) {
                         .jspError(n.getStart(), .invalidConflictingPageDirectiveAttribute
                                 (attr.getIsELIgnored(), value));
                     }
                 } else if ("isErrorPage".equals(attr)) {
                     if (.getIsErrorPage() == null) {
                         .setIsErrorPage(valuen);
                     } else if (!.getIsErrorPage().equals(value)) {
                         .jspError(n.getStart(), .invalidConflictingPageDirectiveAttribute
                                 (attr.getIsErrorPage(), value));
                     }
                 } else if ("errorPage".equals(attr)) {
                     if (.getErrorPage() == null) {
                         .setErrorPage(value);
                     } else if (!.getErrorPage().equals(value)) {
                         .jspError(n.getStart(), .invalidConflictingPageDirectiveAttribute
                                 (attr.getErrorPage(), value));
                     }
                 } else if ("info".equals(attr)) {
                     if (.getInfo() == null) {
                         .setInfo(value);
                     } else if (!.getInfo().equals(value)) {
                         .jspError(n.getStart(), .invalidConflictingPageDirectiveAttribute
                                 (attr.getInfo(), value));
                     }
                 } else if ("pageEncoding".equals(attr)) {
                     if ()
                         .jspError(n.getStart(), .invalidDuplicatePageDirectiveAttribute(attr));
                     // 'pageEncoding' can occur at most once per file
                      = true;
                     String actual = comparePageEncodings(valuen);
                     n.getRoot().setPageEncoding(actual);
                 } else if ("deferredSyntaxAllowedAsLiteral".equals(attr)) {
                     if (.getDeferredSyntaxAllowedAsLiteral() == null) {
                         .setDeferredSyntaxAllowedAsLiteral(valuen,
                                 true);
                     } else if (!.getDeferredSyntaxAllowedAsLiteral()
                             .equals(value)) {
                         .jspError(n.getStart(), .invalidConflictingPageDirectiveAttribute
                                 (attr.getDeferredSyntaxAllowedAsLiteral(), value));
                     }
                 } else if ("trimDirectiveWhitespaces".equals(attr)) {
                     if (.getTrimDirectiveWhitespaces() == null) {
                         .setTrimDirectiveWhitespaces(valuen,
                                 true);
                     } else if (!.getTrimDirectiveWhitespaces().equals(
                             value)) {
                         .jspError(n.getStart(), .invalidConflictingPageDirectiveAttribute
                                 (attr.getTrimDirectiveWhitespaces(), value));
                     }
                 }
             }
 
             // Check for bad combinations
             if (.getBuffer() == 0 && !.isAutoFlush())
 
             // Attributes for imports for this node have been processed by
             // the parsers, just add them to pageInfo.
             .addImports(n.getImports());
         }
 
         public void visit(Node.TagDirective nthrows JasperException {
             // Note: Most of the validation is done in TagFileProcessor
             // when it created a TagInfo object from the
             // tag file in which the directive appeared.
 
             // This method does additional processing to collect page info
 
             Attributes attrs = n.getAttributes();
             for (int i = 0; attrs != null && i < attrs.getLength(); i++) {
                 String attr = attrs.getQName(i);
                 String value = attrs.getValue(i);
 
                 if ("language".equals(attr)) {
                     if (.getLanguage(false) == null) {
                         .setLanguage(valuenfalse);
                     } else if (!.getLanguage(false).equals(value)) {
                         .jspError(n.getStart(), .invalidConflictingTagDirectiveAttributeValues
                                 (attr.getLanguage(false), value));
                     }
                 } else if ("isELIgnored".equals(attr)) {
                     if (.getIsELIgnored() == null) {
                         .setIsELIgnored(valuenfalse);
                     } else if (!.getIsELIgnored().equals(value)) {
                         .jspError(n.getStart(), .invalidConflictingTagDirectiveAttributeValues
                                 (attr.getIsELIgnored(), value));
                     }
                 } else if ("pageEncoding".equals(attr)) {
                     if ()
                         .jspError(n.getStart(), .invalidDuplicateTagDirectiveAttribute(attr));
                      = true;
                     compareTagEncodings(valuen);
                     n.getRoot().setPageEncoding(value);
                 } else if ("deferredSyntaxAllowedAsLiteral".equals(attr)) {
                     if (.getDeferredSyntaxAllowedAsLiteral() == null) {
                         .setDeferredSyntaxAllowedAsLiteral(valuen,
                                 false);
                     } else if (!.getDeferredSyntaxAllowedAsLiteral()
                             .equals(value)) {
                         .jspError(n.getStart(), .invalidConflictingTagDirectiveAttributeValues
                                 (attr.getDeferredSyntaxAllowedAsLiteral(), value));
                     }
                 } else if ("trimDirectiveWhitespaces".equals(attr)) {
                     if (.getTrimDirectiveWhitespaces() == null) {
                         .setTrimDirectiveWhitespaces(valuen,
                                 false);
                     } else if (!.getTrimDirectiveWhitespaces().equals(
                             value)) {
                         .jspError(n.getStart(), .invalidConflictingTagDirectiveAttributeValues
                                 (attr.getTrimDirectiveWhitespaces(), value));
                     }
                 }
             }
 
             // Attributes for imports for this node have been processed by
             // the parsers, just add them to pageInfo.
             .addImports(n.getImports());
         }
 
         public void visit(Node.AttributeDirective nthrows JasperException {
             // Do nothing, since this attribute directive has already been
             // validated by TagFileProcessor when it created a TagInfo object
             // from the tag file in which the directive appeared
         }
 
         public void visit(Node.VariableDirective nthrows JasperException {
             // Do nothing, since this variable directive has already been
             // validated by TagFileProcessor when it created a TagInfo object
             // from the tag file in which the directive appeared
         }
 
         /*
          * Compares page encodings specified in various places, and throws
          * exception in case of page encoding mismatch.
          * 
          * @param pageDirEnc The value of the pageEncoding attribute of the page
          * directive @param pageDir The page directive node
          * 
          * @throws JasperException in case of page encoding mismatch
          */
         private String comparePageEncodings(String thePageDirEnc,
                 Node.PageDirective pageDirthrows JasperException {
 
             Node.Root root = pageDir.getRoot();
             String configEnc = root.getJspConfigPageEncoding();
             String pageDirEnc = thePageDirEnc.toUpperCase(.);
 
             /*
              * Compare the 'pageEncoding' attribute of the page directive with
              * the encoding specified in the JSP config element whose URL
              * pattern matches this page. Treat "UTF-16", "UTF-16BE", and
              * "UTF-16LE" as identical.
              */
             if (configEnc != null) {
                 configEnc = configEnc.toUpperCase(.);
                 if (!pageDirEnc.equals(configEnc)
                         && (!pageDirEnc.startsWith("UTF-16") || !configEnc
                                 .startsWith("UTF-16"))) {
                     .jspError(pageDir.getStart(), 
                             .pageEncodingConflictJspPropertyGroup(configEncpageDirEnc));
                 } else {
                     return configEnc;
                 }
             }
 
             /*
              * Compare the 'pageEncoding' attribute of the page directive with
              * the encoding specified in the XML prolog (only for XML syntax,
              * and only if JSP document contains XML prolog with encoding
              * declaration). Treat "UTF-16", "UTF-16BE", and "UTF-16LE" as
              * identical.
              */
             if ((root.isXmlSyntax() && root.isEncodingSpecifiedInProlog()) || root.isBomPresent()) {
                 String pageEnc = root.getPageEncoding().toUpperCase(.);
                 if (!pageDirEnc.equals(pageEnc)
                         && (!pageDirEnc.startsWith("UTF-16") || !pageEnc
                                 .startsWith("UTF-16"))) {
                     .jspError(pageDir.getStart(),
                             .pageEncodingConflictProlog(pageEncpageDirEnc));
                 } else {
                     return pageEnc;
                 }
             }
             
             return pageDirEnc;
         }
         
         /*
          * Compares page encodings specified in various places, and throws
          * exception in case of page encoding mismatch.
          * 
          * @param pageDirEnc The value of the pageEncoding attribute of the page
          * directive @param pageDir The page directive node
          * 
          * @throws JasperException in case of page encoding mismatch
          */
         private void compareTagEncodings(String pageDirEnc,
                 Node.TagDirective pageDirthrows JasperException {
 
             Node.Root root = pageDir.getRoot();
 
             /*
              * Compare the 'pageEncoding' attribute of the page directive with
              * the encoding specified in the XML prolog (only for XML syntax,
              * and only if JSP document contains XML prolog with encoding
              * declaration). Treat "UTF-16", "UTF-16BE", and "UTF-16LE" as
              * identical.
              */
             if ((root.isXmlSyntax() && root.isEncodingSpecifiedInProlog()) || root.isBomPresent()) {
                 String pageEnc = root.getPageEncoding();
                 if (!pageDirEnc.equals(pageEnc)
                         && (!pageDirEnc.startsWith("UTF-16") || !pageEnc
                                 .startsWith("UTF-16"))) {
                     .jspError(pageDir.getStart(),
                             .pageEncodingConflictProlog(pageEncpageDirEnc));
                 }
             }
         }
 
     }

    
A visitor for validating nodes other than page directives
 
     static class ValidateVisitor extends Node.Visitor {
 
         private PageInfo pageInfo;
 
         private ErrorDispatcher err;
 
         private ClassLoader loader;
 
         private final StringBuilder buf = new StringBuilder(32);
 
         private static final JspUtil.ValidAttribute[] jspRootAttrs = {
                 new JspUtil.ValidAttribute("xsi:schemaLocation"),
                 new JspUtil.ValidAttribute("version"true) };
 
         private static final JspUtil.ValidAttribute[] includeDirectiveAttrs = { new JspUtil.ValidAttribute(
                 "file"true) };
 
         private static final JspUtil.ValidAttribute[] taglibDirectiveAttrs = {
                 new JspUtil.ValidAttribute("uri"),
                 new JspUtil.ValidAttribute("tagdir"),
                 new JspUtil.ValidAttribute("prefix"true) };
 
         private static final JspUtil.ValidAttribute[] includeActionAttrs = {
                 new JspUtil.ValidAttribute("page"truetrue),
                 new JspUtil.ValidAttribute("flush") };
 
         private static final JspUtil.ValidAttribute[] paramActionAttrs = {
                 new JspUtil.ValidAttribute("name"true),
                 new JspUtil.ValidAttribute("value"truetrue) };
 
         private static final JspUtil.ValidAttribute[] forwardActionAttrs = { new JspUtil.ValidAttribute(
                 "page"truetrue) };
 
         private static final JspUtil.ValidAttribute[] getPropertyAttrs = {
                 new JspUtil.ValidAttribute("name"true),
                 new JspUtil.ValidAttribute("property"true) };
 
         private static final JspUtil.ValidAttribute[] setPropertyAttrs = {
                 new JspUtil.ValidAttribute("name"true),
                 new JspUtil.ValidAttribute("property"true),
                 new JspUtil.ValidAttribute("value"falsetrue),
                 new JspUtil.ValidAttribute("param") };
 
         private static final JspUtil.ValidAttribute[] useBeanAttrs = {
                 new JspUtil.ValidAttribute("id"true),
                 new JspUtil.ValidAttribute("scope"),
                 new JspUtil.ValidAttribute("class"),
                 new JspUtil.ValidAttribute("type"),
                 new JspUtil.ValidAttribute("beanName"falsetrue) };
 
         private static final JspUtil.ValidAttribute[] plugInAttrs = {
                 new JspUtil.ValidAttribute("type"true),
                 new JspUtil.ValidAttribute("code"true),
                 new JspUtil.ValidAttribute("codebase"),
                 new JspUtil.ValidAttribute("align"),
                 new JspUtil.ValidAttribute("archive"),
                 new JspUtil.ValidAttribute("height"falsetrue),
                 new JspUtil.ValidAttribute("hspace"),
                 new JspUtil.ValidAttribute("jreversion"),
                 new JspUtil.ValidAttribute("name"),
                 new JspUtil.ValidAttribute("vspace"),
                 new JspUtil.ValidAttribute("width"falsetrue),
                 new JspUtil.ValidAttribute("nspluginurl"),
                 new JspUtil.ValidAttribute("iepluginurl") };
 
         private static final JspUtil.ValidAttribute[] attributeAttrs = {
                 new JspUtil.ValidAttribute("name"true),
                 new JspUtil.ValidAttribute("omit"),
                 new JspUtil.ValidAttribute("trim") };
 
         private static final JspUtil.ValidAttribute[] invokeAttrs = {
                 new JspUtil.ValidAttribute("fragment"true),
                 new JspUtil.ValidAttribute("var"),
                 new JspUtil.ValidAttribute("varReader"),
                 new JspUtil.ValidAttribute("scope") };
 
         private static final JspUtil.ValidAttribute[] doBodyAttrs = {
                 new JspUtil.ValidAttribute("var"),
                 new JspUtil.ValidAttribute("varReader"),
                 new JspUtil.ValidAttribute("scope") };
 
         private static final JspUtil.ValidAttribute[] jspOutputAttrs = {
                 new JspUtil.ValidAttribute("omit-xml-declaration"),
                 new JspUtil.ValidAttribute("doctype-root-element"),
                 new JspUtil.ValidAttribute("doctype-public"),
                 new JspUtil.ValidAttribute("doctype-system") };
 
         private final ExpressionFactory expressionFactory;
 
         /*
          * Constructor
          */
         ValidateVisitor(Compiler compiler) {
             this. = compiler.getPageInfo();
             this. = compiler.getErrorDispatcher();
             this. = compiler.getCompilationContext().getClassLoader();
             // Get the cached EL expression factory for this context
              =
                     JspFactory.getDefaultFactory().getJspApplicationContext(
                     compiler.getCompilationContext().getServletContext()).
                     getExpressionFactory();
         }
 
         public void visit(Node.JspRoot nthrows JasperException {
             JspUtil.checkAttributes(.n);
             String version = n.getTextAttribute("version");
             if (!version.equals("1.2") && !version.equals("2.0") && !version.equals("2.1") && !version.equals("2.2")) {
                 .jspError(n.getStart(), .invalidJspVersionNumber(version));
             }
             visitBody(n);
         }
 
         public void visit(Node.IncludeDirective nthrows JasperException {
             JspUtil.checkAttributes(.n,
                     );
             visitBody(n);
         }
 
         public void visit(Node.TaglibDirective nthrows JasperException {
             JspUtil.checkAttributes(.n,
                     );
             // Either 'uri' or 'tagdir' attribute must be specified
             String uri = n.getAttributeValue("uri");
             String tagdir = n.getAttributeValue("tagdir");
             if (uri == null && tagdir == null) {
                 .jspError(n.getStart(), .invalidTaglibDirectiveMissingLocation());
             }
             if (uri != null && tagdir != null) {
                 .jspError(n.getStart(), .invalidTaglibDirectiveConflictingLocation());
             }
         }
 
         public void visit(Node.ParamAction nthrows JasperException {
             JspUtil.checkAttributes(.n);
             // make sure the value of the 'name' attribute is not a
             // request-time expression
             throwErrorIfExpression(n"name""jsp:param");
             n.setValue(getJspAttribute(null"value"nullnulln
                     .getAttributeValue("value"), java.lang.String.classn,
                     false));
             visitBody(n);
         }
 
         public void visit(Node.ParamsAction nthrows JasperException {
             // Make sure we've got at least one nested jsp:param
             Node.Nodes subElems = n.getBody();
             if (subElems == null) {
                 .jspError(n.getStart(), .invalidEmptyJspParams());
             }
             visitBody(n);
         }
 
         public void visit(Node.IncludeAction nthrows JasperException {
             JspUtil.checkAttributes(.n,
                     );
             n.setPage(getJspAttribute(null"page"nullnulln
                     .getAttributeValue("page"), java.lang.String.classn,
                     false));
             visitBody(n);
         };
 
         public void visit(Node.ForwardAction nthrows JasperException {
             JspUtil.checkAttributes(.n);
             n.setPage(getJspAttribute(null"page"nullnulln
                     .getAttributeValue("page"), java.lang.String.classn,
                     false));
             visitBody(n);
         }
 
         public void visit(Node.GetProperty nthrows JasperException {
             JspUtil.checkAttributes(.n);
         }
 
         public void visit(Node.SetProperty nthrows JasperException {
             JspUtil.checkAttributes(.n);
             String property = n.getTextAttribute("property");
             String param = n.getTextAttribute("param");
             String value = n.getAttributeValue("value");
 
             n.setValue(getJspAttribute(null"value"nullnullvalue,
                     java.lang.Object.classnfalse));
 
             boolean valueSpecified = n.getValue() != null;
 
             if ("*".equals(property)) {
                 if (param != null || valueSpecified)
                     .jspError(n.getStart(), .invalidSetProperty());
             } else if (param != null && valueSpecified) {
                 .jspError(n.getStart(), .invalidSetPropertyEitherParam());
             }
 
             visitBody(n);
         }
 
         public void visit(Node.UseBean nthrows JasperException {
             JspUtil.checkAttributes(.n);
 
             String name = n.getTextAttribute("id");
             String scope = n.getTextAttribute("scope");
             JspUtil.checkScope(scopen);
             String className = n.getTextAttribute("class");
             String type = n.getTextAttribute("type");
             BeanRepository beanInfo = .getBeanRepository();
 
             if (className == null && type == null)
                 .jspError(n.getStart(), .missingUseBeanType());
 
             if (beanInfo.checkVariable(name))
                 .jspError(n.getStart(), .duplicateUseBeanName(name));
 
             if ("session".equals(scope) && !.isSession())
                 .jspError(n.getStart(), .cannotAccessSessionScopeWithUseBean());
 
             Node.JspAttribute jattr = getJspAttribute(null"beanName"null,
                     nulln.getAttributeValue("beanName"),
                     java.lang.String.classnfalse);
             n.setBeanName(jattr);
             if (className != null && jattr != null)
                 .jspError(n.getStart(), .cannotUseBothAttributeAndTypeInUseBean());
 
             if (className == null)
                 className = type;
 
             beanInfo.addBean(nnameclassNamescope);
 
             visitBody(n);
         }
 
         public void visit(Node.PlugIn nthrows JasperException {
             JspUtil.checkAttributes(.n);
 
             throwErrorIfExpression(n"type""jsp:plugin");
             throwErrorIfExpression(n"code""jsp:plugin");
             throwErrorIfExpression(n"codebase""jsp:plugin");
             throwErrorIfExpression(n"align""jsp:plugin");
             throwErrorIfExpression(n"archive""jsp:plugin");
             throwErrorIfExpression(n"hspace""jsp:plugin");
             throwErrorIfExpression(n"jreversion""jsp:plugin");
             throwErrorIfExpression(n"name""jsp:plugin");
             throwErrorIfExpression(n"vspace""jsp:plugin");
             throwErrorIfExpression(n"nspluginurl""jsp:plugin");
             throwErrorIfExpression(n"iepluginurl""jsp:plugin");
 
             String type = n.getTextAttribute("type");
             if (type == null)
                 .jspError(n.getStart(), .missingPluginType());
             if (!type.equals("bean") && !type.equals("applet"))
                 .jspError(n.getStart(), .badPluginType(type));
             if (n.getTextAttribute("code") == null)
                 .jspError(n.getStart(), .missingPluginCode());
 
             Node.JspAttribute width = getJspAttribute(null"width"null,
                     nulln.getAttributeValue("width"), java.lang.String.class,
                     nfalse);
             n.setWidth(width);
 
             Node.JspAttribute height = getJspAttribute(null"height"null,
                     nulln.getAttributeValue("height"),
                     java.lang.String.classnfalse);
             n.setHeight(height);
 
             visitBody(n);
         }
 
         public void visit(Node.NamedAttribute nthrows JasperException {
             JspUtil.checkAttributes(.n);
             visitBody(n);
             if (n.getOmit() != null) {
                 Attributes attrs = n.getAttributes();
                 for (int i = 0; i < attrs.getLength(); i++) {
                     if ("omit".equals(attrs.getLocalName(i))) {
                         n.setOmitAttribute(getJspAttribute(nullattrs.getQName(i),
                                 attrs.getURI(i), attrs.getLocalName(i), 
                                 attrs.getValue(i), java.lang.Boolean.class
                                 nfalse));
                     }
                 }
             }
         }
 
         public void visit(Node.JspBody nthrows JasperException {
             visitBody(n);
         }
 
         public void visit(Node.Declaration nthrows JasperException {
             if (.isScriptingInvalid()) {
                 .jspError(n.getStart(), .invalidScriptingElement());
             }
         }
 
         public void visit(Node.Expression nthrows JasperException {
             if (.isScriptingInvalid()) {
                 .jspError(n.getStart(), .invalidScriptingElement());
             }
         }
 
         public void visit(Node.Scriptlet nthrows JasperException {
             if (.isScriptingInvalid()) {
                 .jspError(n.getStart(), .invalidScriptingElement());
             }
         }
 
         public void visit(Node.ELExpression nthrows JasperException {
             // exit if we are ignoring EL all together
             if (.isELIgnored())
                 return;
 
             // JSP.2.2 - '#{' not allowed in template text
             if (n.getType() == '#') {
                 if (!.isDeferredSyntaxAllowedAsLiteral()) {
                     .jspError(n.getStart(), .invalidDeferredExpressionInTemplateText());
                 } else {
                     return;
                 }
             }
 
             // build expression
             StringBuilder expr = this.getBuffer();
             expr.append(n.getType()).append('{').append(n.getText())
                     .append('}');
             ELNode.Nodes el = ELParser.parse(expr.toString(), 
                     .isDeferredSyntaxAllowedAsLiteral());
 
             // validate/prepare expression
             prepareExpression(elnexpr.toString());
 
             // store it
             n.setEL(el);
         }
 
         public void visit(Node.UninterpretedTag nthrows JasperException {
             if (n.getNamedAttributeNodes().size() != 0) {
                 .jspError(n.getStart(), .invalidJspAttribute());
             }
 
             Attributes attrs = n.getAttributes();
             if (attrs != null) {
                 int attrSize = attrs.getLength();
                 Node.JspAttribute[] jspAttrs = new Node.JspAttribute[attrSize];
                 for (int i = 0; i < attrSizei++) {
                     // JSP.2.2 - '#{' not allowed in template text
                     String value = attrs.getValue(i);
                     if (!.isDeferredSyntaxAllowedAsLiteral()) {
                         if (containsDeferredSyntax(value)) {
                             .jspError(n.getStart(), 
                                     .invalidDeferredExpressionInTemplateText());
                         }
                     }
                     jspAttrs[i] = getJspAttribute(nullattrs.getQName(i),
                             attrs.getURI(i), attrs.getLocalName(i), value
                             java.lang.Object.classnfalse);
                 }
                 n.setJspAttributes(jspAttrs);
             }
 
             visitBody(n);
         }

        
Look for a #{ sequence that isn't preceded by \.
 
         private boolean containsDeferredSyntax(String value) {
             if (value == null) {
                 return false;
             }
             
             int i = 0;
             int len = value.length();
             boolean prevCharIsEscape = false;
             while (i < value.length()) {
                 char c = value.charAt(i);
                 if (c == '#' && (i+1) < len && value.charAt(i+1) == '{' && !prevCharIsEscape) {
                     return true;
                 } else if (c == '\\') {
                     prevCharIsEscape = true;
                 } else {
                     prevCharIsEscape = false;
                 }
                 i++;
             }
             return false;
         }
 
         public void visit(Node.CustomTag nthrows JasperException {
 
             TagInfo tagInfo = n.getTagInfo();
             if (tagInfo == null) {
                 .jspError(n.getStart(), .missingTagInfo(n.getQName()));
             }
 
             /*
              * The bodyconet of a SimpleTag cannot be JSP.
              */
             if (n.implementsSimpleTag()
                     && tagInfo.getBodyContent().equalsIgnoreCase(
                             .)) {
                 .jspError(n.getStart(), .invalidSimpleTagBodyContent(tagInfo
                         .getTagClassName()));
             }
 
             /*
              * If the tag handler declares in the TLD that it supports dynamic
              * attributes, it also must implement the DynamicAttributes
              * interface.
              */
             if (tagInfo.hasDynamicAttributes()
                     && !n.implementsDynamicAttributes()) {
                 .jspError(n.getStart(), .unimplementedDynamicAttributes(n.getQName()));
             }
 
             /*
              * Make sure all required attributes are present, either as
              * attributes or named attributes (<jsp:attribute>). Also make sure
              * that the same attribute is not specified in both attributes or
              * named attributes.
              */
             TagAttributeInfo[] tldAttrs = tagInfo.getAttributes();
             String customActionUri = n.getURI();
             Attributes attrs = n.getAttributes();
             int attrsSize = (attrs == null) ? 0 : attrs.getLength();
             for (int i = 0; i < tldAttrs.lengthi++) {
                 String attr = null;
                 if (attrs != null) {
                     attr = attrs.getValue(tldAttrs[i].getName());
                     if (attr == null) {
                         attr = attrs.getValue(customActionUritldAttrs[i]
                                 .getName());
                     }
                 }
                 Node.NamedAttribute na = n.getNamedAttributeNode(tldAttrs[i]
                         .getName());
 
                 if (tldAttrs[i].isRequired() && attr == null && na == null) {
                     .jspError(n.getStart(), .missingMandatoryAttribute(n.getLocalName(), tldAttrs[i]
                             .getName()));
                 }
                 if (attr != null && na != null) {
                     .jspError(n.getStart(), .duplicateAttribute(tldAttrs[i].getName()));
                 }
             }
 
             Node.Nodes naNodes = n.getNamedAttributeNodes();
             int jspAttrsSize = naNodes.size() + attrsSize;
             Node.JspAttribute[] jspAttrs = null;
             if (jspAttrsSize > 0) {
                 jspAttrs = new Node.JspAttribute[jspAttrsSize];
             }
             Hashtable<StringObjecttagDataAttrs = new Hashtable<StringObject>(attrsSize);
 
             checkXmlAttributes(njspAttrstagDataAttrs);
             checkNamedAttributes(njspAttrsattrsSizetagDataAttrs);
 
             TagData tagData = new TagData(tagDataAttrs);
 
             // JSP.C1: It is a (translation time) error for an action that
             // has one or more variable subelements to have a TagExtraInfo
             // class that returns a non-null object.
             TagExtraInfo tei = tagInfo.getTagExtraInfo();
             if (tei != null && tei.getVariableInfo(tagData) != null
                     && tei.getVariableInfo(tagData).length > 0
                     && tagInfo.getTagVariableInfos().length > 0) {
                 .jspError(n.getStart(), .invalidTeiWithVariableSubelements(n.getQName()));
             }