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   package org.apache.jasper.compiler;
   18   
   19   import java.io.CharArrayWriter;
   20   import java.io.FileNotFoundException;
   21   import java.io.IOException;
   22   import java.io.InputStream;
   23   
   24   import java.util.Iterator;
   25   import java.util.List;
   26   import java.util.jar.JarFile;
   27   
   28   import javax.servlet.jsp.tagext.TagFileInfo;
   29   import javax.servlet.jsp.tagext.TagInfo;
   30   import javax.servlet.jsp.tagext.TagLibraryInfo;
   31   import javax.xml.parsers.SAXParser;
   32   import javax.xml.parsers.SAXParserFactory;
   33   
   34   import org.apache.jasper.JasperException;
   35   import org.apache.jasper.JspCompilationContext;
   36   import org.xml.sax.Attributes;
   37   import org.xml.sax.InputSource;
   38   import org.xml.sax.Locator;
   39   import org.xml.sax.SAXException;
   40   import org.xml.sax.SAXParseException;
   41   import org.xml.sax.XMLReader;
   42   import org.xml.sax.ext.LexicalHandler;
   43   import org.xml.sax.helpers.AttributesImpl;
   44   import org.xml.sax.helpers.DefaultHandler;
   45   
   46   /**
   47    * Class implementing a parser for a JSP document, that is, a JSP page in XML
   48    * syntax.
   49    *
   50    * @author Jan Luehe
   51    * @author Kin-man Chung
   52    */
   53   
   54   class JspDocumentParser
   55       extends DefaultHandler
   56       implements LexicalHandler, TagConstants {
   57   
   58       private static final String JSP_VERSION = "version";
   59       private static final String LEXICAL_HANDLER_PROPERTY =
   60           "http://xml.org/sax/properties/lexical-handler";
   61       private static final String JSP_URI = "http://java.sun.com/JSP/Page";
   62   
   63       private static final EnableDTDValidationException ENABLE_DTD_VALIDATION_EXCEPTION =
   64           new EnableDTDValidationException(
   65               "jsp.error.enable_dtd_validation",
   66               null);
   67   
   68       private ParserController parserController;
   69       private JspCompilationContext ctxt;
   70       private PageInfo pageInfo;
   71       private String path;
   72       private StringBuffer charBuffer;
   73   
   74       // Node representing the XML element currently being parsed
   75       private Node current;
   76   
   77       /*
   78        * Outermost (in the nesting hierarchy) node whose body is declared to be
   79        * scriptless. If a node's body is declared to be scriptless, all its
   80        * nested nodes must be scriptless, too.
   81        */ 
   82       private Node scriptlessBodyNode;
   83   
   84       private Locator locator;
   85   
   86       //Mark representing the start of the current element.  Note
   87       //that locator.getLineNumber() and locator.getColumnNumber()
   88       //return the line and column numbers for the character
   89       //immediately _following_ the current element.  The underlying
   90       //XMl parser eats white space that is not part of character
   91       //data, so for Nodes that are not created from character data,
   92       //this is the best we can do.  But when we parse character data,
   93       //we get an accurate starting location by starting with startMark
   94       //as set by the previous element, and updating it as we advance
   95       //through the characters.
   96       private Mark startMark;
   97   
   98       // Flag indicating whether we are inside DTD declarations
   99       private boolean inDTD;
  100   
  101       private boolean isValidating;
  102   
  103       private ErrorDispatcher err;
  104       private boolean isTagFile;
  105       private boolean directivesOnly;
  106       private boolean isTop;
  107   
  108       // Nesting level of Tag dependent bodies
  109       private int tagDependentNesting = 0;
  110       // Flag set to delay incrmenting tagDependentNesting until jsp:body
  111       // is first encountered
  112       private boolean tagDependentPending = false;
  113   
  114       /*
  115        * Constructor
  116        */
  117       public JspDocumentParser(
  118           ParserController pc,
  119           String path,
  120           boolean isTagFile,
  121           boolean directivesOnly) {
  122           this.parserController = pc;
  123           this.ctxt = pc.getJspCompilationContext();
  124           this.pageInfo = pc.getCompiler().getPageInfo();
  125           this.err = pc.getCompiler().getErrorDispatcher();
  126           this.path = path;
  127           this.isTagFile = isTagFile;
  128           this.directivesOnly = directivesOnly;
  129           this.isTop = true;
  130       }
  131   
  132       /*
  133        * Parses a JSP document by responding to SAX events.
  134        *
  135        * @throws JasperException
  136        */
  137       public static Node.Nodes parse(
  138           ParserController pc,
  139           String path,
  140           JarFile jarFile,
  141           Node parent,
  142           boolean isTagFile,
  143           boolean directivesOnly,
  144           String pageEnc,
  145           String jspConfigPageEnc,
  146           boolean isEncodingSpecifiedInProlog,
  147           boolean isBomPresent)
  148           throws JasperException {
  149   
  150           JspDocumentParser jspDocParser =
  151               new JspDocumentParser(pc, path, isTagFile, directivesOnly);
  152           Node.Nodes pageNodes = null;
  153   
  154           try {
  155   
  156               // Create dummy root and initialize it with given page encodings
  157               Node.Root dummyRoot = new Node.Root(null, parent, true);
  158               dummyRoot.setPageEncoding(pageEnc);
  159               dummyRoot.setJspConfigPageEncoding(jspConfigPageEnc);
  160               dummyRoot.setIsEncodingSpecifiedInProlog(
  161                   isEncodingSpecifiedInProlog);
  162               dummyRoot.setIsBomPresent(isBomPresent);
  163               jspDocParser.current = dummyRoot;
  164               if (parent == null) {
  165                   jspDocParser.addInclude(
  166                       dummyRoot,
  167                       jspDocParser.pageInfo.getIncludePrelude());
  168               } else {
  169                   jspDocParser.isTop = false;
  170               }
  171   
  172               // Parse the input
  173               SAXParser saxParser = getSAXParser(false, jspDocParser);
  174               InputStream inStream = null;
  175               try {
  176                   inStream = JspUtil.getInputStream(path, jarFile,
  177                                                     jspDocParser.ctxt,
  178                                                     jspDocParser.err);
  179                   saxParser.parse(new InputSource(inStream), jspDocParser);
  180               } catch (EnableDTDValidationException e) {
  181                   saxParser = getSAXParser(true, jspDocParser);
  182                   jspDocParser.isValidating = true;
  183                   if (inStream != null) {
  184                       try {
  185                           inStream.close();
  186                       } catch (Exception any) {
  187                       }
  188                   }
  189                   inStream = JspUtil.getInputStream(path, jarFile,
  190                                                     jspDocParser.ctxt,
  191                                                     jspDocParser.err);
  192                   saxParser.parse(new InputSource(inStream), jspDocParser);
  193               } finally {
  194                   if (inStream != null) {
  195                       try {
  196                           inStream.close();
  197                       } catch (Exception any) {
  198                       }
  199                   }
  200               }
  201   
  202               if (parent == null) {
  203                   jspDocParser.addInclude(
  204                       dummyRoot,
  205                       jspDocParser.pageInfo.getIncludeCoda());
  206               }
  207   
  208               // Create Node.Nodes from dummy root
  209               pageNodes = new Node.Nodes(dummyRoot);
  210   
  211           } catch (IOException ioe) {
  212               jspDocParser.err.jspError("jsp.error.data.file.read", path, ioe);
  213           } catch (SAXParseException e) {
  214               jspDocParser.err.jspError
  215                   (new Mark(jspDocParser.ctxt, path, e.getLineNumber(),
  216                             e.getColumnNumber()),
  217                    e.getMessage());
  218           } catch (Exception e) {
  219               jspDocParser.err.jspError(e);
  220           }
  221   
  222           return pageNodes;
  223       }
  224   
  225       /*
  226        * Processes the given list of included files.
  227        *
  228        * This is used to implement the include-prelude and include-coda
  229        * subelements of the jsp-config element in web.xml
  230        */
  231       private void addInclude(Node parent, List files) throws SAXException {
  232           if (files != null) {
  233               Iterator iter = files.iterator();
  234               while (iter.hasNext()) {
  235                   String file = (String)iter.next();
  236                   AttributesImpl attrs = new AttributesImpl();
  237                   attrs.addAttribute("", "file", "file", "CDATA", file);
  238   
  239                   // Create a dummy Include directive node
  240                       Node includeDir =
  241                           new Node.IncludeDirective(attrs, null, // XXX
  242       parent);
  243                   processIncludeDirective(file, includeDir);
  244               }
  245           }
  246       }
  247   
  248       /*
  249        * Receives notification of the start of an element.
  250        *
  251        * This method assigns the given tag attributes to one of 3 buckets:
  252        * 
  253        * - "xmlns" attributes that represent (standard or custom) tag libraries.
  254        * - "xmlns" attributes that do not represent tag libraries.
  255        * - all remaining attributes.
  256        *
  257        * For each "xmlns" attribute that represents a custom tag library, the
  258        * corresponding TagLibraryInfo object is added to the set of custom
  259        * tag libraries.
  260        */
  261       public void startElement(
  262           String uri,
  263           String localName,
  264           String qName,
  265           Attributes attrs)
  266           throws SAXException {
  267   
  268           AttributesImpl taglibAttrs = null;
  269           AttributesImpl nonTaglibAttrs = null;
  270           AttributesImpl nonTaglibXmlnsAttrs = null;
  271   
  272           processChars();
  273   
  274           checkPrefixes(uri, qName, attrs);
  275   
  276           if (directivesOnly &&
  277               !(JSP_URI.equals(uri) && localName.startsWith(DIRECTIVE_ACTION))) {
  278               return;
  279           }
  280   
  281           // jsp:text must not have any subelements
  282           if (JSP_URI.equals(uri) && TEXT_ACTION.equals(current.getLocalName())) {
  283               throw new SAXParseException(
  284                   Localizer.getMessage("jsp.error.text.has_subelement"),
  285                   locator);
  286           }
  287   
  288           startMark = new Mark(ctxt, path, locator.getLineNumber(),
  289                                locator.getColumnNumber());
  290   
  291           if (attrs != null) {
  292               /*
  293                * Notice that due to a bug in the underlying SAX parser, the
  294                * attributes must be enumerated in descending order. 
  295                */
  296               boolean isTaglib = false;
  297               for (int i = attrs.getLength() - 1; i >= 0; i--) {
  298                   isTaglib = false;
  299                   String attrQName = attrs.getQName(i);
  300                   if (!attrQName.startsWith("xmlns")) {
  301                       if (nonTaglibAttrs == null) {
  302                           nonTaglibAttrs = new AttributesImpl();
  303                       }
  304                       nonTaglibAttrs.addAttribute(
  305                           attrs.getURI(i),
  306                           attrs.getLocalName(i),
  307                           attrs.getQName(i),
  308                           attrs.getType(i),
  309                           attrs.getValue(i));
  310                   } else {
  311                       if (attrQName.startsWith("xmlns:jsp")) {
  312                           isTaglib = true;
  313                       } else {
  314                           String attrUri = attrs.getValue(i);
  315                           // TaglibInfo for this uri already established in
  316                           // startPrefixMapping
  317                           isTaglib = pageInfo.hasTaglib(attrUri);
  318                       }
  319                       if (isTaglib) {
  320                           if (taglibAttrs == null) {
  321                               taglibAttrs = new AttributesImpl();
  322                           }
  323                           taglibAttrs.addAttribute(
  324                               attrs.getURI(i),
  325                               attrs.getLocalName(i),
  326                               attrs.getQName(i),
  327                               attrs.getType(i),
  328                               attrs.getValue(i));
  329                       } else {
  330                           if (nonTaglibXmlnsAttrs == null) {
  331                               nonTaglibXmlnsAttrs = new AttributesImpl();
  332                           }
  333                           nonTaglibXmlnsAttrs.addAttribute(
  334                               attrs.getURI(i),
  335                               attrs.getLocalName(i),
  336                               attrs.getQName(i),
  337                               attrs.getType(i),
  338                               attrs.getValue(i));
  339                       }
  340                   }
  341               }
  342           }
  343   
  344           Node node = null;
  345   
  346           if (tagDependentPending && JSP_URI.equals(uri) &&
  347                        localName.equals(BODY_ACTION)) {
  348               tagDependentPending = false;
  349               tagDependentNesting++;
  350               current =
  351                   parseStandardAction(
  352                       qName,
  353                       localName,
  354                       nonTaglibAttrs,
  355                       nonTaglibXmlnsAttrs,
  356                       taglibAttrs,
  357                       startMark,
  358                       current);
  359               return;
  360           }
  361   
  362           if (tagDependentPending && JSP_URI.equals(uri) &&
  363                        localName.equals(ATTRIBUTE_ACTION)) {
  364               current =
  365                   parseStandardAction(
  366                       qName,
  367                       localName,
  368                       nonTaglibAttrs,
  369                       nonTaglibXmlnsAttrs,
  370                       taglibAttrs,
  371                       startMark,
  372                       current);
  373               return;
  374           }
  375   
  376           if (tagDependentPending) {
  377               tagDependentPending = false;
  378               tagDependentNesting++;
  379           }
  380   
  381           if (tagDependentNesting > 0) {
  382               node =
  383                   new Node.UninterpretedTag(
  384                       qName,
  385                       localName,
  386                       nonTaglibAttrs,
  387                       nonTaglibXmlnsAttrs,
  388                       taglibAttrs,
  389                       startMark,
  390                       current);
  391           } else if (JSP_URI.equals(uri)) {
  392               node =
  393                   parseStandardAction(
  394                       qName,
  395                       localName,
  396                       nonTaglibAttrs,
  397                       nonTaglibXmlnsAttrs,
  398                       taglibAttrs,
  399                       startMark,
  400                       current);
  401           } else {
  402               node =
  403                   parseCustomAction(
  404                       qName,
  405                       localName,
  406                       uri,
  407                       nonTaglibAttrs,
  408                       nonTaglibXmlnsAttrs,
  409                       taglibAttrs,
  410                       startMark,
  411                       current);
  412               if (node == null) {
  413                   node =
  414                       new Node.UninterpretedTag(
  415                           qName,
  416                           localName,
  417                           nonTaglibAttrs,
  418                           nonTaglibXmlnsAttrs,
  419                           taglibAttrs,
  420                           startMark,
  421                           current);
  422               } else {
  423                   // custom action
  424                   String bodyType = getBodyType((Node.CustomTag) node);
  425   
  426                   if (scriptlessBodyNode == null
  427                           && bodyType.equalsIgnoreCase(TagInfo.BODY_CONTENT_SCRIPTLESS)) {
  428                       scriptlessBodyNode = node;
  429                   }
  430                   else if (TagInfo.BODY_CONTENT_TAG_DEPENDENT.equalsIgnoreCase(bodyType)) {
  431                       tagDependentPending = true;
  432                   }
  433               }
  434           }
  435   
  436           current = node;
  437       }
  438   
  439       /*
  440        * Receives notification of character data inside an element.
  441        *
  442        * The SAX does not call this method with all of the template text, but may
  443        * invoke this method with chunks of it.  This is a problem when we try
  444        * to determine if the text contains only whitespaces, or when we are
  445        * looking for an EL expression string.  Therefore it is necessary to
  446        * buffer and concatenate the chunks and process the concatenated text 
  447        * later (at beginTag and endTag)
  448        *
  449        * @param buf The characters
  450        * @param offset The start position in the character array
  451        * @param len The number of characters to use from the character array
  452        *
  453        * @throws SAXException
  454        */
  455       public void characters(char[] buf, int offset, int len) {
  456   
  457           if (charBuffer == null) {
  458               charBuffer = new StringBuffer();
  459           }
  460           charBuffer.append(buf, offset, len);
  461       }
  462   
  463       private void processChars() throws SAXException {
  464   
  465           if (charBuffer == null || directivesOnly) {
  466               return;
  467           }
  468   
  469           /*
  470            * JSP.6.1.1: All textual nodes that have only white space are to be
  471            * dropped from the document, except for nodes in a jsp:text element,
  472            * and any leading and trailing white-space-only textual nodes in a
  473            * jsp:attribute whose 'trim' attribute is set to FALSE, which are to
  474            * be kept verbatim.
  475            * JSP.6.2.3 defines white space characters.
  476            */
  477           boolean isAllSpace = true;
  478           if (!(current instanceof Node.JspText)
  479               && !(current instanceof Node.NamedAttribute)) {
  480               for (int i = 0; i < charBuffer.length(); i++) {
  481                   if (!(charBuffer.charAt(i) == ' '
  482                       || charBuffer.charAt(i) == '\n'
  483                       || charBuffer.charAt(i) == '\r'
  484                       || charBuffer.charAt(i) == '\t')) {
  485                       isAllSpace = false;
  486                       break;
  487                   }
  488               }
  489           }
  490   
  491           if (!isAllSpace && tagDependentPending) {
  492               tagDependentPending = false;
  493               tagDependentNesting++;
  494           }
  495   
  496           if (tagDependentNesting > 0) {
  497               if (charBuffer.length() > 0) {
  498                   new Node.TemplateText(charBuffer.toString(), startMark, current);
  499               }
  500               startMark = new Mark(ctxt, path, locator.getLineNumber(),
  501                                    locator.getColumnNumber());
  502               charBuffer = null;
  503               return;
  504           }
  505   
  506           if ((current instanceof Node.JspText)
  507               || (current instanceof Node.NamedAttribute)
  508               || !isAllSpace) {
  509   
  510               int line = startMark.getLineNumber();
  511               int column = startMark.getColumnNumber();
  512   
  513               CharArrayWriter ttext = new CharArrayWriter();
  514               int lastCh = 0, elType = 0;
  515               for (int i = 0; i < charBuffer.length(); i++) {
  516   
  517                   int ch = charBuffer.charAt(i);
  518                   if (ch == '\n') {
  519                       column = 1;
  520                       line++;
  521                   } else {
  522                       column++;
  523                   }
  524                   if ((lastCh == '$' || lastCh == '#') && ch == '{') {
  525                       elType = lastCh;
  526                       if (ttext.size() > 0) {
  527                           new Node.TemplateText(
  528                               ttext.toString(),
  529                               startMark,
  530                               current);
  531                           ttext = new CharArrayWriter();
  532                           //We subtract two from the column number to
  533                           //account for the '[$,#]{' that we've already parsed
  534                           startMark = new Mark(ctxt, path, line, column - 2);
  535                       }
  536                       // following "${" || "#{" to first unquoted "}"
  537                       i++;
  538                       boolean singleQ = false;
  539                       boolean doubleQ = false;
  540                       lastCh = 0;
  541                       for (;; i++) {
  542                           if (i >= charBuffer.length()) {
  543                               throw new SAXParseException(
  544                                   Localizer.getMessage(
  545                                       "jsp.error.unterminated",
  546                                       (char) elType + "{"),
  547                                   locator);
  548   
  549                           }
  550                           ch = charBuffer.charAt(i);
  551                           if (ch == '\n') {
  552                               column = 1;
  553                               line++;
  554                           } else {
  555                               column++;
  556                           }
  557                           if (lastCh == '\\' && (singleQ || doubleQ)) {
  558                               ttext.write(ch);
  559                               lastCh = 0;
  560                               continue;
  561                           }
  562                           if (ch == '}') {
  563                               new Node.ELExpression((char) elType,
  564                                   ttext.toString(),
  565                                   startMark,
  566                                   current);
  567                               ttext = new CharArrayWriter();
  568                               startMark = new Mark(ctxt, path, line, column);
  569                               break;
  570                           }
  571                           if (ch == '"')
  572                               doubleQ = !doubleQ;
  573                           else if (ch == '\'')
  574                               singleQ = !singleQ;
  575   
  576                           ttext.write(ch);
  577                           lastCh = ch;
  578                       }
  579                   } else if (lastCh == '\\' && (ch == '$' || ch == '#')) {
  580                       ttext.write(ch);
  581                       ch = 0;  // Not start of EL anymore
  582                   } else {
  583                       if (lastCh == '$' || lastCh == '#' || lastCh == '\\') {
  584                           ttext.write(lastCh);
  585                       }
  586                       if (ch != '$' && ch != '#' && ch != '\\') {
  587                           ttext.write(ch);
  588                       }
  589                   }
  590                   lastCh = ch;
  591               }
  592               if (lastCh == '$' || lastCh == '#' || lastCh == '\\') {
  593                   ttext.write(lastCh);
  594               }
  595               if (ttext.size() > 0) {
  596                   new Node.TemplateText(ttext.toString(), startMark, current);
  597               }
  598           }
  599           startMark = new Mark(ctxt, path, locator.getLineNumber(),
  600                                locator.getColumnNumber());
  601   
  602           charBuffer = null;
  603       }
  604   
  605       /*
  606        * Receives notification of the end of an element.
  607        */
  608       public void endElement(String uri, String localName, String qName)
  609           throws SAXException {
  610   
  611           processChars();
  612   
  613           if (directivesOnly &&
  614               !(JSP_URI.equals(uri) && localName.startsWith(DIRECTIVE_ACTION))) {
  615               return;
  616           }
  617   
  618           if (current instanceof Node.NamedAttribute) {
  619               boolean isTrim = ((Node.NamedAttribute)current).isTrim();
  620               Node.Nodes subElems = ((Node.NamedAttribute)current).getBody();
  621               for (int i = 0; subElems != null && i < subElems.size(); i++) {
  622                   Node subElem = subElems.getNode(i);
  623                   if (!(subElem instanceof Node.TemplateText)) {
  624                       continue;
  625                   }
  626                   // Ignore any whitespace (including spaces, carriage returns,
  627                   // line feeds, and tabs, that appear at the beginning and at
  628                   // the end of the body of the <jsp:attribute> action, if the
  629                   // action's 'trim' attribute is set to TRUE (default).
  630                   // In addition, any textual nodes in the <jsp:attribute> that
  631                   // have only white space are dropped from the document, with
  632                   // the exception of leading and trailing white-space-only
  633                   // textual nodes in a <jsp:attribute> whose 'trim' attribute
  634                   // is set to FALSE, which must be kept verbatim.
  635                   if (i == 0) {
  636                       if (isTrim) {
  637                           ((Node.TemplateText)subElem).ltrim();
  638                       }
  639                   } else if (i == subElems.size() - 1) {
  640                       if (isTrim) {
  641                           ((Node.TemplateText)subElem).rtrim();
  642                       }
  643                   } else {
  644                       if (((Node.TemplateText)subElem).isAllSpace()) {
  645                           subElems.remove(subElem);
  646                       }
  647                   }
  648               }
  649           } else if (current instanceof Node.ScriptingElement) {
  650               checkScriptingBody((Node.ScriptingElement)current);
  651           }
  652   
  653           if ( isTagDependent(current)) {
  654               tagDependentNesting--;
  655           }
  656   
  657           if (scriptlessBodyNode != null
  658                   && current.equals(scriptlessBodyNode)) {
  659               scriptlessBodyNode = null;
  660           }
  661   
  662           if (current.getParent() != null) {
  663               current = current.getParent();
  664           }
  665       }
  666   
  667       /*
  668        * Receives the document locator.
  669        *
  670        * @param locator the document locator
  671        */
  672       public void setDocumentLocator(Locator locator) {
  673           this.locator = locator;
  674       }
  675   
  676       /*
  677        * See org.xml.sax.ext.LexicalHandler.
  678        */
  679       public void comment(char[] buf, int offset, int len) throws SAXException {
  680   
  681           processChars();  // Flush char buffer and remove white spaces
  682   
  683           // ignore comments in the DTD
  684           if (!inDTD) {
  685               startMark =
  686                   new Mark(
  687                       ctxt,
  688                       path,
  689                       locator.getLineNumber(),
  690                       locator.getColumnNumber());
  691               new Node.Comment(new String(buf, offset, len), startMark, current);
  692           }
  693       }
  694   
  695       /*
  696        * See org.xml.sax.ext.LexicalHandler.
  697        */
  698       public void startCDATA() throws SAXException {
  699   
  700           processChars();  // Flush char buffer and remove white spaces
  701           startMark = new Mark(ctxt, path, locator.getLineNumber(),
  702                                locator.getColumnNumber());
  703       }
  704   
  705       /*
  706        * See org.xml.sax.ext.LexicalHandler.
  707        */
  708       public void endCDATA() throws SAXException {
  709           processChars();  // Flush char buffer and remove white spaces
  710       }
  711   
  712       /*
  713        * See org.xml.sax.ext.LexicalHandler.
  714        */
  715       public void startEntity(String name) throws SAXException {
  716           // do nothing
  717       }
  718   
  719       /*
  720        * See org.xml.sax.ext.LexicalHandler.
  721        */
  722       public void endEntity(String name) throws SAXException {
  723           // do nothing
  724       }
  725   
  726       /*
  727        * See org.xml.sax.ext.LexicalHandler.
  728        */
  729       public void startDTD(String name, String publicId, String systemId)
  730           throws SAXException {
  731           if (!isValidating) {
  732               fatalError(ENABLE_DTD_VALIDATION_EXCEPTION);
  733           }
  734   
  735           inDTD = true;
  736       }
  737   
  738       /*
  739        * See org.xml.sax.ext.LexicalHandler.
  740        */
  741       public void endDTD() throws SAXException {
  742           inDTD = false;
  743       }
  744   
  745       /*
  746        * Receives notification of a non-recoverable error.
  747        */
  748       public void fatalError(SAXParseException e) throws SAXException {
  749           throw e;
  750       }
  751   
  752       /*
  753        * Receives notification of a recoverable error.
  754        */
  755       public void error(SAXParseException e) throws SAXException {
  756           throw e;
  757       }
  758   
  759       /*
  760        * Receives notification of the start of a Namespace mapping. 
  761        */
  762       public void startPrefixMapping(String prefix, String uri)
  763           throws SAXException {
  764           TagLibraryInfo taglibInfo;
  765   
  766           if (directivesOnly && !(JSP_URI.equals(uri))) {
  767               return;
  768           }
  769           
  770           try {
  771               taglibInfo = getTaglibInfo(prefix, uri);
  772           } catch (JasperException je) {
  773               throw new SAXParseException(
  774                   Localizer.getMessage("jsp.error.could.not.add.taglibraries"),
  775                   locator,
  776                   je);
  777           }
  778   
  779           if (taglibInfo != null) {
  780               if (pageInfo.getTaglib(uri) == null) {
  781                   pageInfo.addTaglib(uri, taglibInfo);
  782               }
  783               pageInfo.pushPrefixMapping(prefix, uri);
  784           } else {
  785               pageInfo.pushPrefixMapping(prefix, null);
  786           }
  787       }
  788   
  789       /*
  790        * Receives notification of the end of a Namespace mapping. 
  791        */
  792       public void endPrefixMapping(String prefix) throws SAXException {
  793   
  794           if (directivesOnly) {
  795               String uri = pageInfo.getURI(prefix);
  796               if (!JSP_URI.equals(uri)) {
  797                   return;
  798               }
  799           }
  800   
  801           pageInfo.popPrefixMapping(prefix);
  802       }
  803   
  804       //*********************************************************************
  805       // Private utility methods
  806   
  807       private Node parseStandardAction(
  808           String qName,
  809           String localName,
  810           Attributes nonTaglibAttrs,
  811           Attributes nonTaglibXmlnsAttrs,
  812           Attributes taglibAttrs,
  813           Mark start,
  814           Node parent)
  815           throws SAXException {
  816   
  817           Node node = null;
  818   
  819           if (localName.equals(ROOT_ACTION)) {
  820               if (!(current instanceof Node.Root)) {
  821                   throw new SAXParseException(
  822                       Localizer.getMessage("jsp.error.nested_jsproot"),
  823                       locator);
  824               }
  825               node =
  826                   new Node.JspRoot(
  827                       qName,
  828                       nonTaglibAttrs,
  829                       nonTaglibXmlnsAttrs,
  830                       taglibAttrs,
  831                       start,
  832                       current);
  833               if (isTop) {
  834                   pageInfo.setHasJspRoot(true);
  835               }
  836           } else if (localName.equals(PAGE_DIRECTIVE_ACTION)) {
  837               if (isTagFile) {
  838                   throw new SAXParseException(
  839                       Localizer.getMessage(
  840                           "jsp.error.action.istagfile",
  841                           localName),
  842                       locator);
  843               }
  844               node =
  845                   new Node.PageDirective(
  846                       qName,
  847                       nonTaglibAttrs,
  848                       nonTaglibXmlnsAttrs,
  849                       taglibAttrs,
  850                       start,
  851                       current);
  852               String imports = nonTaglibAttrs.getValue("import");
  853               // There can only be one 'import' attribute per page directive
  854               if (imports != null) {
  855                   ((Node.PageDirective)node).addImport(imports);
  856               }
  857           } else if (localName.equals(INCLUDE_DIRECTIVE_ACTION)) {
  858               node =
  859                   new Node.IncludeDirective(
  860                       qName,
  861                       nonTaglibAttrs,
  862                       nonTaglibXmlnsAttrs,
  863                       taglibAttrs,
  864                       start,
  865                       current);
  866               processIncludeDirective(nonTaglibAttrs.getValue("file"), node);
  867           } else if (localName.equals(DECLARATION_ACTION)) {
  868               if (scriptlessBodyNode != null) {
  869                   // We're nested inside a node whose body is
  870                   // declared to be scriptless
  871                   throw new SAXParseException(
  872                       Localizer.getMessage(
  873                           "jsp.error.no.scriptlets",
  874                           localName),
  875                       locator);
  876               }
  877               node =
  878                   new Node.Declaration(
  879                       qName,
  880                       nonTaglibXmlnsAttrs,
  881                       taglibAttrs,
  882                       start,
  883                       current);
  884           } else if (localName.equals(SCRIPTLET_ACTION)) {
  885               if (scriptlessBodyNode != null) {
  886                   // We're nested inside a node whose body is
  887                   // declared to be scriptless
  888                   throw new SAXParseException(
  889                       Localizer.getMessage(
  890                           "jsp.error.no.scriptlets",
  891                           localName),
  892                       locator);
  893               }
  894               node =
  895                   new Node.Scriptlet(
  896                       qName,
  897                       nonTaglibXmlnsAttrs,
  898                       taglibAttrs,
  899                       start,
  900                       current);
  901           } else if (localName.equals(EXPRESSION_ACTION)) {
  902               if (scriptlessBodyNode != null) {
  903                   // We're nested inside a node whose body is
  904                   // declared to be scriptless
  905                   throw new SAXParseException(
  906                       Localizer.getMessage(
  907                           "jsp.error.no.scriptlets",
  908                           localName),
  909                       locator);
  910               }
  911               node =
  912                   new Node.Expression(
  913                       qName,
  914                       nonTaglibXmlnsAttrs,
  915                       taglibAttrs,
  916                       start,
  917                       current);
  918           } else if (localName.equals(USE_BEAN_ACTION)) {
  919               node =
  920                   new Node.UseBean(
  921                       qName,
  922                       nonTaglibAttrs,
  923                       nonTaglibXmlnsAttrs,
  924                       taglibAttrs,
  925                       start,
  926                       current);
  927           } else if (localName.equals(SET_PROPERTY_ACTION)) {
  928               node =
  929                   new Node.SetProperty(
  930                       qName,
  931                       nonTaglibAttrs,
  932                       nonTaglibXmlnsAttrs,
  933                       taglibAttrs,
  934                       start,
  935                       current);
  936           } else if (localName.equals(GET_PROPERTY_ACTION)) {
  937               node =
  938                   new Node.GetProperty(
  939                       qName,
  940                       nonTaglibAttrs,
  941                       nonTaglibXmlnsAttrs,
  942                       taglibAttrs,
  943                       start,
  944                       current);
  945           } else if (localName.equals(INCLUDE_ACTION)) {
  946               node =
  947                   new Node.IncludeAction(
  948                       qName,
  949                       nonTaglibAttrs,
  950                       nonTaglibXmlnsAttrs,
  951                       taglibAttrs,
  952                       start,
  953                       current);
  954           } else if (localName.equals(FORWARD_ACTION)) {
  955               node =
  956                   new Node.ForwardAction(
  957                       qName,
  958                       nonTaglibAttrs,
  959                       nonTaglibXmlnsAttrs,
  960                       taglibAttrs,
  961                       start,
  962                       current);
  963           } else if (localName.equals(PARAM_ACTION)) {
  964               node =
  965                   new Node.ParamAction(
  966                       qName,
  967                       nonTaglibAttrs,
  968                       nonTaglibXmlnsAttrs,
  969                       taglibAttrs,
  970                       start,
  971                       current);
  972           } else if (localName.equals(PARAMS_ACTION)) {
  973               node =
  974                   new Node.ParamsAction(
  975                       qName,
  976                       nonTaglibXmlnsAttrs,
  977                       taglibAttrs,
  978                       start,
  979                       current);
  980           } else if (localName.equals(PLUGIN_ACTION)) {
  981               node =
  982                   new Node.PlugIn(
  983                       qName,
  984                       nonTaglibAttrs,
  985                       nonTaglibXmlnsAttrs,
  986                       taglibAttrs,
  987                       start,
  988                       current);
  989           } else if (localName.equals(TEXT_ACTION)) {
  990               node =
  991                   new Node.JspText(
  992                       qName,
  993                       nonTaglibXmlnsAttrs,
  994                       taglibAttrs,
  995                       start,
  996                       current);
  997           } else if (localName.equals(BODY_ACTION)) {
  998               node =
  999                   new Node.JspBody(
 1000                       qName,
 1001                       nonTaglibXmlnsAttrs,
 1002                       taglibAttrs,
 1003                       start,
 1004                       current);
 1005           } else if (localName.equals(ATTRIBUTE_ACTION)) {
 1006               node =
 1007                   new Node.NamedAttribute(
 1008                       qName,
 1009                       nonTaglibAttrs,
 1010                       nonTaglibXmlnsAttrs,
 1011                       taglibAttrs,
 1012                       start,
 1013                       current);
 1014           } else if (localName.equals(OUTPUT_ACTION)) {
 1015               node =
 1016                   new Node.JspOutput(
 1017                       qName,
 1018                       nonTaglibAttrs,
 1019                       nonTaglibXmlnsAttrs,
 1020                       taglibAttrs,
 1021                       start,
 1022                       current);
 1023           } else if (localName.equals(TAG_DIRECTIVE_ACTION)) {
 1024               if (!isTagFile) {
 1025                   throw new SAXParseException(
 1026                       Localizer.getMessage(
 1027                           "jsp.error.action.isnottagfile",
 1028                           localName),
 1029                       locator);
 1030               }
 1031               node =
 1032                   new Node.TagDirective(
 1033                       qName,
 1034                       nonTaglibAttrs,
 1035                       nonTaglibXmlnsAttrs,
 1036                       taglibAttrs,
 1037                       start,
 1038                       current);
 1039               String imports = nonTaglibAttrs.getValue("import");
 1040               // There can only be one 'import' attribute per tag directive
 1041               if (imports != null) {
 1042                   ((Node.TagDirective)node).addImport(imports);
 1043               }
 1044           } else if (localName.equals(ATTRIBUTE_DIRECTIVE_ACTION)) {
 1045               if (!isTagFile) {
 1046                   throw new SAXParseException(
 1047                       Localizer.getMessage(
 1048                           "jsp.error.action.isnottagfile",
 1049                           localName),
 1050                       locator);
 1051               }
 1052               node =
 1053                   new Node.AttributeDirective(
 1054                       qName,
 1055                       nonTaglibAttrs,
 1056                       nonTaglibXmlnsAttrs,
 1057                       taglibAttrs,
 1058                       start,
 1059                       current);
 1060           } else if (localName.equals(VARIABLE_DIRECTIVE_ACTION)) {
 1061               if (!isTagFile) {
 1062                   throw new SAXParseException(
 1063                       Localizer.getMessage(
 1064                           "jsp.error.action.isnottagfile",
 1065                           localName),
 1066                       locator);
 1067               }
 1068               node =
 1069                   new Node.VariableDirective(
 1070                       qName,
 1071                       nonTaglibAttrs,
 1072                       nonTaglibXmlnsAttrs,
 1073                       taglibAttrs,
 1074                       start,
 1075                       current);
 1076           } else if (localName.equals(INVOKE_ACTION)) {
 1077               if (!isTagFile) {
 1078                   throw new SAXParseException(
 1079                       Localizer.getMessage(
 1080                           "jsp.error.action.isnottagfile",
 1081                           localName),
 1082                       locator);
 1083               }
 1084               node =
 1085                   new Node.InvokeAction(
 1086                       qName,
 1087                       nonTaglibAttrs,
 1088                       nonTaglibXmlnsAttrs,
 1089                       taglibAttrs,
 1090                       start,
 1091                       current);
 1092           } else if (localName.equals(DOBODY_ACTION)) {
 1093               if (!isTagFile) {
 1094                   throw new SAXParseException(
 1095                       Localizer.getMessage(
 1096                           "jsp.error.action.isnottagfile",
 1097                           localName),
 1098                       locator);
 1099               }
 1100               node =
 1101                   new Node.DoBodyAction(
 1102                       qName,
 1103                       nonTaglibAttrs,
 1104                       nonTaglibXmlnsAttrs,
 1105                       taglibAttrs,
 1106                       start,
 1107                       current);
 1108           } else if (localName.equals(ELEMENT_ACTION)) {
 1109               node =
 1110                   new Node.JspElement(
 1111                       qName,
 1112                       nonTaglibAttrs,
 1113                       nonTaglibXmlnsAttrs,
 1114                       taglibAttrs,
 1115                       start,
 1116                       current);
 1117           } else if (localName.equals(FALLBACK_ACTION)) {
 1118               node =
 1119                   new Node.FallBackAction(
 1120                       qName,
 1121                       nonTaglibXmlnsAttrs,
 1122                       taglibAttrs,
 1123                       start,
 1124                       current);
 1125           } else {
 1126               throw new SAXParseException(
 1127                   Localizer.getMessage(
 1128                       "jsp.error.xml.badStandardAction",
 1129                       localName),
 1130                   locator);
 1131           }
 1132   
 1133           return node;
 1134       }
 1135   
 1136       /*
 1137        * Checks if the XML element with the given tag name is a custom action,
 1138        * and returns the corresponding Node object.
 1139        */
 1140       private Node parseCustomAction(
 1141           String qName,
 1142           String localName,
 1143           String uri,
 1144           Attributes nonTaglibAttrs,
 1145           Attributes nonTaglibXmlnsAttrs,
 1146           Attributes taglibAttrs,
 1147           Mark start,
 1148           Node parent)
 1149           throws SAXException {
 1150   
 1151           // Check if this is a user-defined (custom) tag
 1152           TagLibraryInfo tagLibInfo = pageInfo.getTaglib(uri);
 1153           if (tagLibInfo == null) {
 1154               return null;
 1155           }
 1156   
 1157           TagInfo tagInfo = tagLibInfo.getTag(localName);
 1158           TagFileInfo tagFileInfo = tagLibInfo.getTagFile(localName);
 1159           if (tagInfo == null && tagFileInfo == null) {
 1160               throw new SAXException(
 1161                   Localizer.getMessage("jsp.error.xml.bad_tag", localName, uri));
 1162           }
 1163           Class tagHandlerClass = null;
 1164           if (tagInfo != null) {
 1165               String handlerClassName = tagInfo.getTagClassName();
 1166               try {
 1167                   tagHandlerClass =
 1168                       ctxt.getClassLoader().loadClass(handlerClassName);
 1169               } catch (Exception e) {
 1170                   throw new SAXException(
 1171                       Localizer.getMessage("jsp.error.loadclass.taghandler",
 1172                                            handlerClassName,
 1173                                            qName),
 1174                       e);
 1175               }
 1176           }
 1177   
 1178           String prefix = "";
 1179           int colon = qName.indexOf(':');
 1180           if (colon != -1) {
 1181               prefix = qName.substring(0, colon);
 1182           }
 1183   
 1184           Node.CustomTag ret = null;
 1185           if (tagInfo != null) {
 1186               ret =
 1187                   new Node.CustomTag(
 1188                       qName,
 1189                       prefix,
 1190                       localName,
 1191                       uri,
 1192                       nonTaglibAttrs,
 1193                       nonTaglibXmlnsAttrs,
 1194                       taglibAttrs,
 1195                       start,
 1196                       parent,
 1197                       tagInfo,
 1198                       tagHandlerClass);
 1199           } else {
 1200               ret =
 1201                   new Node.CustomTag(
 1202                       qName,
 1203                       prefix,
 1204                       localName,
 1205                       uri,
 1206                       nonTaglibAttrs,
 1207                       nonTaglibXmlnsAttrs,
 1208                       taglibAttrs,
 1209                       start,
 1210                       parent,
 1211                       tagFileInfo);
 1212           }
 1213   
 1214           return ret;
 1215       }
 1216   
 1217       /*
 1218        * Creates the tag library associated with the given uri namespace, and
 1219        * returns it.
 1220        *
 1221        * @param prefix The prefix of the xmlns attribute
 1222        * @param uri The uri namespace (value of the xmlns attribute)
 1223        *
 1224        * @return The tag library associated with the given uri namespace
 1225        */
 1226       private TagLibraryInfo getTaglibInfo(String prefix, String uri)
 1227           throws JasperException {
 1228   
 1229           TagLibraryInfo result = null;
 1230   
 1231           if (uri.startsWith(URN_JSPTAGDIR)) {
 1232               // uri (of the form "urn:jsptagdir:path") references tag file dir
 1233               String tagdir = uri.substring(URN_JSPTAGDIR.length());
 1234               result =
 1235                   new ImplicitTagLibraryInfo(
 1236                       ctxt,
 1237                       parserController,
 1238                       pageInfo,
 1239                       prefix,
 1240                       tagdir,
 1241                       err);
 1242           } else {
 1243               // uri references TLD file
 1244               boolean isPlainUri = false;
 1245               if (uri.startsWith(URN_JSPTLD)) {
 1246                   // uri is of the form "urn:jsptld:path"
 1247                   uri = uri.substring(URN_JSPTLD.length());
 1248               } else {
 1249                   isPlainUri = true;
 1250               }
 1251   
 1252               String[] location = ctxt.getTldLocation(uri);
 1253               if (location != null || !isPlainUri) {
 1254                   if (ctxt.getOptions().isCaching()) {
 1255                       result = (TagLibraryInfoImpl) ctxt.getOptions().getCache().get(uri);
 1256                   }
 1257                   if (result == null) {
 1258                       /*
 1259                        * If the uri value is a plain uri, a translation error must
 1260                        * not be generated if the uri is not found in the taglib map.
 1261                        * Instead, any actions in the namespace defined by the uri
 1262                        * value must be treated as uninterpreted.
 1263                        */
 1264                       result =
 1265                           new TagLibraryInfoImpl(
 1266                               ctxt,
 1267                               parserController,
 1268                               pageInfo,
 1269                               prefix,
 1270                               uri,
 1271                               location,
 1272                               err);
 1273                       if (ctxt.getOptions().isCaching()) {
 1274                           ctxt.getOptions().getCache().put(uri, result);
 1275                       }
 1276                   }
 1277               }
 1278           }
 1279   
 1280           return result;
 1281       }
 1282   
 1283       /*
 1284        * Ensures that the given body only contains nodes that are instances of
 1285        * TemplateText.
 1286        *
 1287        * This check is performed only for the body of a scripting (that is:
 1288        * declaration, scriptlet, or expression) element, after the end tag of a
 1289        * scripting element has been reached.
 1290        */
 1291       private void checkScriptingBody(Node.ScriptingElement scriptingElem)
 1292           throws SAXException {
 1293           Node.Nodes body = scriptingElem.getBody();
 1294           if (body != null) {
 1295               int size = body.size();
 1296               for (int i = 0; i < size; i++) {
 1297                   Node n = body.getNode(i);
 1298                   if (!(n instanceof Node.TemplateText)) {
 1299                       String elemType = SCRIPTLET_ACTION;
 1300                       if (scriptingElem instanceof Node.Declaration)
 1301                           elemType = DECLARATION_ACTION;
 1302                       if (scriptingElem instanceof Node.Expression)
 1303                           elemType = EXPRESSION_ACTION;
 1304                       String msg =
 1305                           Localizer.getMessage(
 1306                               "jsp.error.parse.xml.scripting.invalid.body",
 1307                               elemType);
 1308                       throw new SAXException(msg);
 1309                   }
 1310               }
 1311           }
 1312       }
 1313   
 1314       /*
 1315        * Parses the given file included via an include directive.
 1316        *
 1317        * @param fname The path to the included resource, as specified by the
 1318        * 'file' attribute of the include directive
 1319        * @param parent The Node representing the include directive
 1320        */
 1321       private void processIncludeDirective(String fname, Node parent)
 1322           throws SAXException {
 1323   
 1324           if (fname == null) {
 1325               return;
 1326           }
 1327   
 1328           try {
 1329               parserController.parse(fname, parent, null);
 1330           } catch (FileNotFoundException fnfe) {
 1331               throw new SAXParseException(
 1332                   Localizer.getMessage("jsp.error.file.not.found", fname),
 1333                   locator,
 1334                   fnfe);
 1335           } catch (Exception e) {
 1336               throw new SAXException(e);
 1337           }
 1338       }
 1339   
 1340       /*
 1341        * Checks an element's given URI, qname, and attributes to see if any
 1342        * of them hijack the 'jsp' prefix, that is, bind it to a namespace other
 1343        * than http://java.sun.com/JSP/Page.
 1344        *
 1345        * @param uri The element's URI
 1346        * @param qName The element's qname
 1347        * @param attrs The element's attributes
 1348        */
 1349       private void checkPrefixes(String uri, String qName, Attributes attrs) {
 1350   
 1351           checkPrefix(uri, qName);
 1352   
 1353           int len = attrs.getLength();
 1354           for (int i = 0; i < len; i++) {
 1355               checkPrefix(attrs.getURI(i), attrs.getQName(i));
 1356           }
 1357       }
 1358   
 1359       /*
 1360        * Checks the given URI and qname to see if they hijack the 'jsp' prefix,
 1361        * which would be the case if qName contained the 'jsp' prefix and
 1362        * uri was different from http://java.sun.com/JSP/Page.
 1363        *
 1364        * @param uri The URI to check
 1365        * @param qName The qname to check
 1366        */
 1367       private void checkPrefix(String uri, String qName) {
 1368   
 1369           int index = qName.indexOf(':');
 1370           if (index != -1) {
 1371               String prefix = qName.substring(0, index);
 1372               pageInfo.addPrefix(prefix);
 1373               if ("jsp".equals(prefix) && !JSP_URI.equals(uri)) {
 1374                   pageInfo.setIsJspPrefixHijacked(true);
 1375               }
 1376           }
 1377       }
 1378   
 1379       /*
 1380        * Gets SAXParser.
 1381        *
 1382        * @param validating Indicates whether the requested SAXParser should
 1383        * be validating
 1384        * @param jspDocParser The JSP document parser
 1385        *
 1386        * @return The SAXParser
 1387        */
 1388       private static SAXParser getSAXParser(
 1389           boolean validating,
 1390           JspDocumentParser jspDocParser)
 1391           throws Exception {
 1392   
 1393           SAXParserFactory factory = SAXParserFactory.newInstance();
 1394           factory.setNamespaceAware(true);
 1395   
 1396           // Preserve xmlns attributes
 1397           factory.setFeature(
 1398               "http://xml.org/sax/features/namespace-prefixes",
 1399               true);
 1400           factory.setValidating(validating);
 1401           //factory.setFeature(
 1402           //    "http://xml.org/sax/features/validation",
 1403           //    validating);
 1404           
 1405           // Configure the parser
 1406           SAXParser saxParser = factory.newSAXParser();
 1407           XMLReader xmlReader = saxParser.getXMLReader();
 1408           xmlReader.setProperty(LEXICAL_HANDLER_PROPERTY, jspDocParser);
 1409           xmlReader.setErrorHandler(jspDocParser);
 1410   
 1411           return saxParser;
 1412       }
 1413   
 1414       /*
 1415        * Exception indicating that a DOCTYPE declaration is present, but
 1416        * validation is turned off.
 1417        */
 1418       private static class EnableDTDValidationException
 1419           extends SAXParseException {
 1420   
 1421           EnableDTDValidationException(String message, Locator loc) {
 1422               super(message, loc);
 1423           }
 1424       }
 1425   
 1426       private static String getBodyType(Node.CustomTag custom) {
 1427   
 1428           if (custom.getTagInfo() != null) {
 1429               return custom.getTagInfo().getBodyContent();
 1430           }
 1431   
 1432           return custom.getTagFileInfo().getTagInfo().getBodyContent();
 1433       }
 1434   
 1435       private boolean isTagDependent(Node n) {
 1436   
 1437           if (n instanceof Node.CustomTag) {
 1438               String bodyType = getBodyType((Node.CustomTag) n);
 1439               return
 1440                   TagInfo.BODY_CONTENT_TAG_DEPENDENT.equalsIgnoreCase(bodyType);
 1441           }
 1442           return false;
 1443       }
 1444   }

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