Source Code Cross Referenced for Parser.java in  » Sevlet-Container » tomcat-jasper2 » org » apache » jasper » compiler » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Sevlet Container » tomcat jasper2 » org.apache.jasper.compiler 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 1999,2004 The Apache Software Foundation.
0003:         * 
0004:         * Licensed under the Apache License, Version 2.0 (the "License");
0005:         * you may not use this file except in compliance with the License.
0006:         * You may obtain a copy of the License at
0007:         * 
0008:         *      http://www.apache.org/licenses/LICENSE-2.0
0009:         * 
0010:         * Unless required by applicable law or agreed to in writing, software
0011:         * distributed under the License is distributed on an "AS IS" BASIS,
0012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013:         * See the License for the specific language governing permissions and
0014:         * limitations under the License.
0015:         */
0016:        package org.apache.jasper.compiler;
0017:
0018:        import java.io.CharArrayWriter;
0019:        import java.io.FileNotFoundException;
0020:        import java.net.URL;
0021:        import java.util.Iterator;
0022:        import java.util.List;
0023:
0024:        import javax.servlet.jsp.tagext.TagAttributeInfo;
0025:        import javax.servlet.jsp.tagext.TagFileInfo;
0026:        import javax.servlet.jsp.tagext.TagInfo;
0027:        import javax.servlet.jsp.tagext.TagLibraryInfo;
0028:
0029:        import org.apache.jasper.Constants;
0030:        import org.apache.jasper.JasperException;
0031:        import org.apache.jasper.JspCompilationContext;
0032:        import org.xml.sax.Attributes;
0033:        import org.xml.sax.helpers.AttributesImpl;
0034:
0035:        /**
0036:         * This class implements a parser for a JSP page (non-xml view).
0037:         * JSP page grammar is included here for reference.  The token '#'
0038:         * that appears in the production indicates the current input token
0039:         * location in the production.
0040:         * 
0041:         * @author Kin-man Chung
0042:         * @author Shawn Bayern
0043:         * @author Mark Roth
0044:         */
0045:
0046:        class Parser implements  TagConstants {
0047:
0048:            private ParserController parserController;
0049:            private JspCompilationContext ctxt;
0050:            private JspReader reader;
0051:            private String currentFile;
0052:            private Mark start;
0053:            private ErrorDispatcher err;
0054:            private int scriptlessCount;
0055:            private boolean isTagFile;
0056:            private boolean directivesOnly;
0057:            private URL jarFileUrl;
0058:            private PageInfo pageInfo;
0059:
0060:            // Virtual body content types, to make parsing a little easier.
0061:            // These are not accessible from outside the parser.
0062:            private static final String JAVAX_BODY_CONTENT_PARAM = "JAVAX_BODY_CONTENT_PARAM";
0063:            private static final String JAVAX_BODY_CONTENT_PLUGIN = "JAVAX_BODY_CONTENT_PLUGIN";
0064:            private static final String JAVAX_BODY_CONTENT_TEMPLATE_TEXT = "JAVAX_BODY_CONTENT_TEMPLATE_TEXT";
0065:
0066:            /**
0067:             * The constructor
0068:             */
0069:            private Parser(ParserController pc, JspReader reader,
0070:                    boolean isTagFile, boolean directivesOnly, URL jarFileUrl) {
0071:                this .parserController = pc;
0072:                this .ctxt = pc.getJspCompilationContext();
0073:                this .pageInfo = pc.getCompiler().getPageInfo();
0074:                this .err = pc.getCompiler().getErrorDispatcher();
0075:                this .reader = reader;
0076:                this .currentFile = reader.mark().getFile();
0077:                this .scriptlessCount = 0;
0078:                this .isTagFile = isTagFile;
0079:                this .directivesOnly = directivesOnly;
0080:                this .jarFileUrl = jarFileUrl;
0081:                start = reader.mark();
0082:            }
0083:
0084:            /**
0085:             * The main entry for Parser
0086:             * 
0087:             * @param pc The ParseController, use for getting other objects in compiler
0088:             *		 and for parsing included pages
0089:             * @param reader To read the page
0090:             * @param parent The parent node to this page, null for top level page
0091:             * @return list of nodes representing the parsed page
0092:             */
0093:            public static Node.Nodes parse(ParserController pc,
0094:                    JspReader reader, Node parent, boolean isTagFile,
0095:                    boolean directivesOnly, URL jarFileUrl, String pageEnc,
0096:                    String jspConfigPageEnc, boolean isDefaultPageEncoding)
0097:                    throws JasperException {
0098:
0099:                Parser parser = new Parser(pc, reader, isTagFile,
0100:                        directivesOnly, jarFileUrl);
0101:
0102:                Node.Root root = new Node.Root(reader.mark(), parent, false);
0103:                root.setPageEncoding(pageEnc);
0104:                root.setJspConfigPageEncoding(jspConfigPageEnc);
0105:                root.setIsDefaultPageEncoding(isDefaultPageEncoding);
0106:
0107:                if (directivesOnly) {
0108:                    parser.parseTagFileDirectives(root);
0109:                    return new Node.Nodes(root);
0110:                }
0111:
0112:                // For the Top level page, add inlcude-prelude and include-coda
0113:                PageInfo pageInfo = pc.getCompiler().getPageInfo();
0114:                if (parent == null) {
0115:                    parser.addInclude(root, pageInfo.getIncludePrelude());
0116:                }
0117:                while (reader.hasMoreInput()) {
0118:                    parser.parseElements(root);
0119:                }
0120:                if (parent == null) {
0121:                    parser.addInclude(root, pageInfo.getIncludeCoda());
0122:                }
0123:
0124:                Node.Nodes page = new Node.Nodes(root);
0125:                return page;
0126:            }
0127:
0128:            /**
0129:             * Attributes ::= (S Attribute)* S?
0130:             */
0131:            Attributes parseAttributes() throws JasperException {
0132:                AttributesImpl attrs = new AttributesImpl();
0133:
0134:                reader.skipSpaces();
0135:                while (parseAttribute(attrs))
0136:                    reader.skipSpaces();
0137:
0138:                return attrs;
0139:            }
0140:
0141:            /**
0142:             * Parse Attributes for a reader, provided for external use
0143:             */
0144:            public static Attributes parseAttributes(ParserController pc,
0145:                    JspReader reader) throws JasperException {
0146:                Parser tmpParser = new Parser(pc, reader, false, false, null);
0147:                return tmpParser.parseAttributes();
0148:            }
0149:
0150:            /**
0151:             * Attribute ::= Name S? Eq S?
0152:             *               (   '"<%=' RTAttributeValueDouble
0153:             *                 | '"' AttributeValueDouble
0154:             *                 | "'<%=" RTAttributeValueSingle
0155:             *                 | "'" AttributeValueSingle
0156:             *               }
0157:             * Note: JSP and XML spec does not allow while spaces around Eq.  It is
0158:             * added to be backward compatible with Tomcat, and with other xml parsers.
0159:             */
0160:            private boolean parseAttribute(AttributesImpl attrs)
0161:                    throws JasperException {
0162:
0163:                // Get the qualified name
0164:                String qName = parseName();
0165:                if (qName == null)
0166:                    return false;
0167:
0168:                // Determine prefix and local name components
0169:                String localName = qName;
0170:                String uri = "";
0171:                int index = qName.indexOf(':');
0172:                if (index != -1) {
0173:                    String prefix = qName.substring(0, index);
0174:                    uri = pageInfo.getURI(prefix);
0175:                    if (uri == null) {
0176:                        err.jspError(reader.mark(),
0177:                                "jsp.error.attribute.invalidPrefix", prefix);
0178:                    }
0179:                    localName = qName.substring(index + 1);
0180:                }
0181:
0182:                reader.skipSpaces();
0183:                if (!reader.matches("="))
0184:                    err.jspError(reader.mark(), "jsp.error.attribute.noequal");
0185:
0186:                reader.skipSpaces();
0187:                char quote = (char) reader.nextChar();
0188:                if (quote != '\'' && quote != '"')
0189:                    err.jspError(reader.mark(), "jsp.error.attribute.noquote");
0190:
0191:                String watchString = "";
0192:                if (reader.matches("<%="))
0193:                    watchString = "%>";
0194:                watchString = watchString + quote;
0195:
0196:                String attrValue = parseAttributeValue(watchString);
0197:                attrs.addAttribute(uri, localName, qName, "CDATA", attrValue);
0198:                return true;
0199:            }
0200:
0201:            /**
0202:             * Name ::= (Letter | '_' | ':') (Letter | Digit | '.' | '_' | '-' | ':')*
0203:             */
0204:            private String parseName() throws JasperException {
0205:                char ch = (char) reader.peekChar();
0206:                if (Character.isLetter(ch) || ch == '_' || ch == ':') {
0207:                    StringBuffer buf = new StringBuffer();
0208:                    buf.append(ch);
0209:                    reader.nextChar();
0210:                    ch = (char) reader.peekChar();
0211:                    while (Character.isLetter(ch) || Character.isDigit(ch)
0212:                            || ch == '.' || ch == '_' || ch == '-' || ch == ':') {
0213:                        buf.append(ch);
0214:                        reader.nextChar();
0215:                        ch = (char) reader.peekChar();
0216:                    }
0217:                    return buf.toString();
0218:                }
0219:                return null;
0220:            }
0221:
0222:            /**
0223:             * AttributeValueDouble ::= (QuotedChar - '"')*
0224:             *				('"' | <TRANSLATION_ERROR>)
0225:             * RTAttributeValueDouble ::= ((QuotedChar - '"')* - ((QuotedChar-'"')'%>"')
0226:             *				  ('%>"' | TRANSLATION_ERROR)
0227:             */
0228:            private String parseAttributeValue(String watch)
0229:                    throws JasperException {
0230:                Mark start = reader.mark();
0231:                Mark stop = reader.skipUntilIgnoreEsc(watch);
0232:                if (stop == null) {
0233:                    err.jspError(start, "jsp.error.attribute.unterminated",
0234:                            watch);
0235:                }
0236:
0237:                String ret = parseQuoted(reader.getText(start, stop));
0238:                if (watch.length() == 1) // quote
0239:                    return ret;
0240:
0241:                // putback delimiter '<%=' and '%>', since they are needed if the
0242:                // attribute does not allow RTexpression.
0243:                return "<%=" + ret + "%>";
0244:            }
0245:
0246:            /**
0247:             * QuotedChar ::=   '&apos;'
0248:             *	              | '&quot;'
0249:             *                | '\\'
0250:             *                | '\"'
0251:             *                | "\'"
0252:             *                | '\>'
0253:             *                | '\$'
0254:             *                | Char
0255:             */
0256:            private String parseQuoted(String tx) {
0257:                StringBuffer buf = new StringBuffer();
0258:                int size = tx.length();
0259:                int i = 0;
0260:                while (i < size) {
0261:                    char ch = tx.charAt(i);
0262:                    if (ch == '&') {
0263:                        if (i + 5 < size && tx.charAt(i + 1) == 'a'
0264:                                && tx.charAt(i + 2) == 'p'
0265:                                && tx.charAt(i + 3) == 'o'
0266:                                && tx.charAt(i + 4) == 's'
0267:                                && tx.charAt(i + 5) == ';') {
0268:                            buf.append('\'');
0269:                            i += 6;
0270:                        } else if (i + 5 < size && tx.charAt(i + 1) == 'q'
0271:                                && tx.charAt(i + 2) == 'u'
0272:                                && tx.charAt(i + 3) == 'o'
0273:                                && tx.charAt(i + 4) == 't'
0274:                                && tx.charAt(i + 5) == ';') {
0275:                            buf.append('"');
0276:                            i += 6;
0277:                        } else {
0278:                            buf.append(ch);
0279:                            ++i;
0280:                        }
0281:                    } else if (ch == '\\' && i + 1 < size) {
0282:                        ch = tx.charAt(i + 1);
0283:                        if (ch == '\\' || ch == '\"' || ch == '\'' || ch == '>') {
0284:                            buf.append(ch);
0285:                            i += 2;
0286:                        } else if (ch == '$') {
0287:                            // Replace "\$" with some special char.  XXX hack!
0288:                            buf.append(Constants.ESC);
0289:                            i += 2;
0290:                        } else {
0291:                            buf.append('\\');
0292:                            ++i;
0293:                        }
0294:                    } else {
0295:                        buf.append(ch);
0296:                        ++i;
0297:                    }
0298:                }
0299:                return buf.toString();
0300:            }
0301:
0302:            private String parseScriptText(String tx) {
0303:                CharArrayWriter cw = new CharArrayWriter();
0304:                int size = tx.length();
0305:                int i = 0;
0306:                while (i < size) {
0307:                    char ch = tx.charAt(i);
0308:                    if (i + 2 < size && ch == '%' && tx.charAt(i + 1) == '\\'
0309:                            && tx.charAt(i + 2) == '>') {
0310:                        cw.write('%');
0311:                        cw.write('>');
0312:                        i += 3;
0313:                    } else {
0314:                        cw.write(ch);
0315:                        ++i;
0316:                    }
0317:                }
0318:                cw.close();
0319:                return cw.toString();
0320:            }
0321:
0322:            /*
0323:             * Invokes parserController to parse the included page
0324:             */
0325:            private void processIncludeDirective(String file, Node parent)
0326:                    throws JasperException {
0327:                if (file == null) {
0328:                    return;
0329:                }
0330:
0331:                try {
0332:                    parserController.parse(file, parent, jarFileUrl);
0333:                } catch (FileNotFoundException ex) {
0334:                    err.jspError(start, "jsp.error.file.not.found", file);
0335:                } catch (Exception ex) {
0336:                    err.jspError(start, ex.getMessage());
0337:                }
0338:            }
0339:
0340:            /*
0341:             * Parses a page directive with the following syntax:
0342:             *   PageDirective ::= ( S Attribute)*
0343:             */
0344:            private void parsePageDirective(Node parent) throws JasperException {
0345:                Attributes attrs = parseAttributes();
0346:                Node.PageDirective n = new Node.PageDirective(attrs, start,
0347:                        parent);
0348:
0349:                /*
0350:                 * A page directive may contain multiple 'import' attributes, each of
0351:                 * which consists of a comma-separated list of package names.
0352:                 * Store each list with the node, where it is parsed.
0353:                 */
0354:                for (int i = 0; i < attrs.getLength(); i++) {
0355:                    if ("import".equals(attrs.getQName(i))) {
0356:                        n.addImport(attrs.getValue(i));
0357:                    }
0358:                }
0359:            }
0360:
0361:            /*
0362:             * Parses an include directive with the following syntax:
0363:             *   IncludeDirective ::= ( S Attribute)*
0364:             */
0365:            private void parseIncludeDirective(Node parent)
0366:                    throws JasperException {
0367:                Attributes attrs = parseAttributes();
0368:
0369:                // Included file expanded here
0370:                Node includeNode = new Node.IncludeDirective(attrs, start,
0371:                        parent);
0372:                processIncludeDirective(attrs.getValue("file"), includeNode);
0373:            }
0374:
0375:            /**
0376:             * Add a list of files.  This is used for implementing include-prelude
0377:             * and include-coda of jsp-config element in web.xml
0378:             */
0379:            private void addInclude(Node parent, List files)
0380:                    throws JasperException {
0381:                if (files != null) {
0382:                    Iterator iter = files.iterator();
0383:                    while (iter.hasNext()) {
0384:                        String file = (String) iter.next();
0385:                        AttributesImpl attrs = new AttributesImpl();
0386:                        attrs.addAttribute("", "file", "file", "CDATA", file);
0387:
0388:                        // Create a dummy Include directive node
0389:                        Node includeNode = new Node.IncludeDirective(attrs,
0390:                                reader.mark(), parent);
0391:                        processIncludeDirective(file, includeNode);
0392:                    }
0393:                }
0394:            }
0395:
0396:            /*
0397:             * Parses a taglib directive with the following syntax:
0398:             *   Directive ::= ( S Attribute)*
0399:             */
0400:            private void parseTaglibDirective(Node parent)
0401:                    throws JasperException {
0402:
0403:                Attributes attrs = parseAttributes();
0404:                String uri = attrs.getValue("uri");
0405:                String prefix = attrs.getValue("prefix");
0406:                if (prefix != null) {
0407:                    Mark prevMark = pageInfo.getNonCustomTagPrefix(prefix);
0408:                    if (prevMark != null) {
0409:                        err.jspError(reader.mark(),
0410:                                "jsp.error.prefix.use_before_dcl", prefix,
0411:                                prevMark.getFile(), ""
0412:                                        + prevMark.getLineNumber());
0413:                    }
0414:                    if (uri != null) {
0415:                        String uriPrev = pageInfo.getURI(prefix);
0416:                        if (uriPrev != null && !uriPrev.equals(uri)) {
0417:                            err.jspError(reader.mark(),
0418:                                    "jsp.error.prefix.refined", prefix, uri,
0419:                                    uriPrev);
0420:                        }
0421:                        if (pageInfo.getTaglib(uri) == null) {
0422:                            String[] location = ctxt.getTldLocation(uri);
0423:                            pageInfo.addTaglib(uri, new TagLibraryInfoImpl(
0424:                                    ctxt, parserController, prefix, uri,
0425:                                    location, err));
0426:                        }
0427:                        pageInfo.addPrefixMapping(prefix, uri);
0428:                    } else {
0429:                        String tagdir = attrs.getValue("tagdir");
0430:                        if (tagdir != null) {
0431:                            String urnTagdir = URN_JSPTAGDIR + tagdir;
0432:                            if (pageInfo.getTaglib(urnTagdir) == null) {
0433:                                pageInfo.addTaglib(urnTagdir,
0434:                                        new ImplicitTagLibraryInfo(ctxt,
0435:                                                parserController, prefix,
0436:                                                tagdir, err));
0437:                            }
0438:                            pageInfo.addPrefixMapping(prefix, urnTagdir);
0439:                        }
0440:                    }
0441:                }
0442:
0443:                new Node.TaglibDirective(attrs, start, parent);
0444:            }
0445:
0446:            /*
0447:             * Parses a directive with the following syntax:
0448:             *   Directive ::= S? (   'page' PageDirective
0449:             *			    | 'include' IncludeDirective
0450:             *			    | 'taglib' TagLibDirective)
0451:             *		       S? '%>'
0452:             *
0453:             *   TagDirective ::= S? ('tag' PageDirective
0454:             *			    | 'include' IncludeDirective
0455:             *			    | 'taglib' TagLibDirective)
0456:             *                      | 'attribute AttributeDirective
0457:             *                      | 'variable VariableDirective
0458:             *		       S? '%>'
0459:             */
0460:            private void parseDirective(Node parent) throws JasperException {
0461:                reader.skipSpaces();
0462:
0463:                String directive = null;
0464:                if (reader.matches("page")) {
0465:                    directive = "&lt;%@ page";
0466:                    if (isTagFile) {
0467:                        err.jspError(reader.mark(),
0468:                                "jsp.error.directive.istagfile", directive);
0469:                    }
0470:                    parsePageDirective(parent);
0471:                } else if (reader.matches("include")) {
0472:                    directive = "&lt;%@ include";
0473:                    parseIncludeDirective(parent);
0474:                } else if (reader.matches("taglib")) {
0475:                    if (directivesOnly) {
0476:                        // No need to get the tagLibInfo objects.  This alos suppresses
0477:                        // parsing of any tag files used in this tag file.
0478:                        return;
0479:                    }
0480:                    directive = "&lt;%@ taglib";
0481:                    parseTaglibDirective(parent);
0482:                } else if (reader.matches("tag")) {
0483:                    directive = "&lt;%@ tag";
0484:                    if (!isTagFile) {
0485:                        err.jspError(reader.mark(),
0486:                                "jsp.error.directive.isnottagfile", directive);
0487:                    }
0488:                    parseTagDirective(parent);
0489:                } else if (reader.matches("attribute")) {
0490:                    directive = "&lt;%@ attribute";
0491:                    if (!isTagFile) {
0492:                        err.jspError(reader.mark(),
0493:                                "jsp.error.directive.isnottagfile", directive);
0494:                    }
0495:                    parseAttributeDirective(parent);
0496:                } else if (reader.matches("variable")) {
0497:                    directive = "&lt;%@ variable";
0498:                    if (!isTagFile) {
0499:                        err.jspError(reader.mark(),
0500:                                "jsp.error.directive.isnottagfile", directive);
0501:                    }
0502:                    parseVariableDirective(parent);
0503:                } else {
0504:                    err.jspError(reader.mark(), "jsp.error.invalid.directive");
0505:                }
0506:
0507:                reader.skipSpaces();
0508:                if (!reader.matches("%>")) {
0509:                    err.jspError(start, "jsp.error.unterminated", directive);
0510:                }
0511:            }
0512:
0513:            /*
0514:             * Parses a directive with the following syntax:
0515:             *
0516:             *   XMLJSPDirectiveBody ::= S? (   ( 'page' PageDirectiveAttrList
0517:             *                                    S? ( '/>' | ( '>' S? ETag ) )
0518:             *                               | ( 'include' IncludeDirectiveAttrList
0519:             *                                    S? ( '/>' | ( '>' S? ETag ) )
0520:             *                           | <TRANSLATION_ERROR>
0521:             *
0522:             *   XMLTagDefDirectiveBody ::= (   ( 'tag' TagDirectiveAttrList
0523:             *                                    S? ( '/>' | ( '>' S? ETag ) )
0524:             *                                | ( 'include' IncludeDirectiveAttrList
0525:             *                                    S? ( '/>' | ( '>' S? ETag ) )
0526:             *                                | ( 'attribute' AttributeDirectiveAttrList
0527:             *                                    S? ( '/>' | ( '>' S? ETag ) )
0528:             *                                | ( 'variable' VariableDirectiveAttrList
0529:             *                                    S? ( '/>' | ( '>' S? ETag ) )
0530:             *                              )
0531:             *                            | <TRANSLATION_ERROR>
0532:             */
0533:            private void parseXMLDirective(Node parent) throws JasperException {
0534:                reader.skipSpaces();
0535:
0536:                String eTag = null;
0537:                if (reader.matches("page")) {
0538:                    eTag = "jsp:directive.page";
0539:                    if (isTagFile) {
0540:                        err.jspError(reader.mark(),
0541:                                "jsp.error.directive.istagfile", "&lt;" + eTag);
0542:                    }
0543:                    parsePageDirective(parent);
0544:                } else if (reader.matches("include")) {
0545:                    eTag = "jsp:directive.include";
0546:                    parseIncludeDirective(parent);
0547:                } else if (reader.matches("tag")) {
0548:                    eTag = "jsp:directive.tag";
0549:                    if (!isTagFile) {
0550:                        err.jspError(reader.mark(),
0551:                                "jsp.error.directive.isnottagfile", "&lt;"
0552:                                        + eTag);
0553:                    }
0554:                    parseTagDirective(parent);
0555:                } else if (reader.matches("attribute")) {
0556:                    eTag = "jsp:directive.attribute";
0557:                    if (!isTagFile) {
0558:                        err.jspError(reader.mark(),
0559:                                "jsp.error.directive.isnottagfile", "&lt;"
0560:                                        + eTag);
0561:                    }
0562:                    parseAttributeDirective(parent);
0563:                } else if (reader.matches("variable")) {
0564:                    eTag = "jsp:directive.variable";
0565:                    if (!isTagFile) {
0566:                        err.jspError(reader.mark(),
0567:                                "jsp.error.directive.isnottagfile", "&lt;"
0568:                                        + eTag);
0569:                    }
0570:                    parseVariableDirective(parent);
0571:                } else {
0572:                    err.jspError(reader.mark(), "jsp.error.invalid.directive");
0573:                }
0574:
0575:                reader.skipSpaces();
0576:                if (reader.matches(">")) {
0577:                    reader.skipSpaces();
0578:                    if (!reader.matchesETag(eTag)) {
0579:                        err.jspError(start, "jsp.error.unterminated", "&lt;"
0580:                                + eTag);
0581:                    }
0582:                } else if (!reader.matches("/>")) {
0583:                    err
0584:                            .jspError(start, "jsp.error.unterminated", "&lt;"
0585:                                    + eTag);
0586:                }
0587:            }
0588:
0589:            /*
0590:             * Parses a tag directive with the following syntax:
0591:             *   PageDirective ::= ( S Attribute)*
0592:             */
0593:            private void parseTagDirective(Node parent) throws JasperException {
0594:                Attributes attrs = parseAttributes();
0595:                Node.TagDirective n = new Node.TagDirective(attrs, start,
0596:                        parent);
0597:
0598:                /*
0599:                 * A page directive may contain multiple 'import' attributes, each of
0600:                 * which consists of a comma-separated list of package names.
0601:                 * Store each list with the node, where it is parsed.
0602:                 */
0603:                for (int i = 0; i < attrs.getLength(); i++) {
0604:                    if ("import".equals(attrs.getQName(i))) {
0605:                        n.addImport(attrs.getValue(i));
0606:                    }
0607:                }
0608:            }
0609:
0610:            /*
0611:             * Parses a attribute directive with the following syntax:
0612:             *   AttributeDirective ::= ( S Attribute)*
0613:             */
0614:            private void parseAttributeDirective(Node parent)
0615:                    throws JasperException {
0616:                Attributes attrs = parseAttributes();
0617:                Node.AttributeDirective n = new Node.AttributeDirective(attrs,
0618:                        start, parent);
0619:            }
0620:
0621:            /*
0622:             * Parses a variable directive with the following syntax:
0623:             *   PageDirective ::= ( S Attribute)*
0624:             */
0625:            private void parseVariableDirective(Node parent)
0626:                    throws JasperException {
0627:                Attributes attrs = parseAttributes();
0628:                Node.VariableDirective n = new Node.VariableDirective(attrs,
0629:                        start, parent);
0630:            }
0631:
0632:            /*
0633:             * JSPCommentBody ::= (Char* - (Char* '--%>')) '--%>'
0634:             */
0635:            private void parseComment(Node parent) throws JasperException {
0636:                start = reader.mark();
0637:                Mark stop = reader.skipUntil("--%>");
0638:                if (stop == null) {
0639:                    err.jspError(start, "jsp.error.unterminated", "&lt;%--");
0640:                }
0641:
0642:                new Node.Comment(reader.getText(start, stop), start, parent);
0643:            }
0644:
0645:            /*
0646:             * DeclarationBody ::= (Char* - (char* '%>')) '%>'
0647:             */
0648:            private void parseDeclaration(Node parent) throws JasperException {
0649:                start = reader.mark();
0650:                Mark stop = reader.skipUntil("%>");
0651:                if (stop == null) {
0652:                    err.jspError(start, "jsp.error.unterminated", "&lt;%!");
0653:                }
0654:
0655:                new Node.Declaration(parseScriptText(reader
0656:                        .getText(start, stop)), start, parent);
0657:            }
0658:
0659:            /*
0660:             * XMLDeclarationBody ::=   ( S? '/>' )
0661:             *                        | ( S? '>' (Char* - (char* '<')) CDSect?)* ETag
0662:             *                        | <TRANSLATION_ERROR>
0663:             * CDSect ::= CDStart CData CDEnd
0664:             * CDStart ::= '<![CDATA['
0665:             * CData ::= (Char* - (Char* ']]>' Char*))
0666:             * CDEnd ::= ']]>'
0667:             */
0668:            private void parseXMLDeclaration(Node parent)
0669:                    throws JasperException {
0670:                reader.skipSpaces();
0671:                if (!reader.matches("/>")) {
0672:                    if (!reader.matches(">")) {
0673:                        err.jspError(start, "jsp.error.unterminated",
0674:                                "&lt;jsp:declaration&gt;");
0675:                    }
0676:                    Mark stop;
0677:                    String text;
0678:                    while (true) {
0679:                        start = reader.mark();
0680:                        stop = reader.skipUntil("<");
0681:                        if (stop == null) {
0682:                            err.jspError(start, "jsp.error.unterminated",
0683:                                    "&lt;jsp:declaration&gt;");
0684:                        }
0685:                        text = parseScriptText(reader.getText(start, stop));
0686:                        new Node.Declaration(text, start, parent);
0687:                        if (reader.matches("![CDATA[")) {
0688:                            start = reader.mark();
0689:                            stop = reader.skipUntil("]]>");
0690:                            if (stop == null) {
0691:                                err.jspError(start, "jsp.error.unterminated",
0692:                                        "CDATA");
0693:                            }
0694:                            text = parseScriptText(reader.getText(start, stop));
0695:                            new Node.Declaration(text, start, parent);
0696:                        } else {
0697:                            break;
0698:                        }
0699:                    }
0700:
0701:                    if (!reader.matchesETagWithoutLessThan("jsp:declaration")) {
0702:                        err.jspError(start, "jsp.error.unterminated",
0703:                                "&lt;jsp:declaration&gt;");
0704:                    }
0705:                }
0706:            }
0707:
0708:            /*
0709:             * ExpressionBody ::= (Char* - (char* '%>')) '%>'
0710:             */
0711:            private void parseExpression(Node parent) throws JasperException {
0712:                start = reader.mark();
0713:                Mark stop = reader.skipUntil("%>");
0714:                if (stop == null) {
0715:                    err.jspError(start, "jsp.error.unterminated", "&lt;%=");
0716:                }
0717:
0718:                new Node.Expression(
0719:                        parseScriptText(reader.getText(start, stop)), start,
0720:                        parent);
0721:            }
0722:
0723:            /*
0724:             * XMLExpressionBody ::=   ( S? '/>' )
0725:             *                       | ( S? '>' (Char* - (char* '<')) CDSect?)* ETag )
0726:             *                       | <TRANSLATION_ERROR>
0727:             */
0728:            private void parseXMLExpression(Node parent) throws JasperException {
0729:                reader.skipSpaces();
0730:                if (!reader.matches("/>")) {
0731:                    if (!reader.matches(">")) {
0732:                        err.jspError(start, "jsp.error.unterminated",
0733:                                "&lt;jsp:expression&gt;");
0734:                    }
0735:                    Mark stop;
0736:                    String text;
0737:                    while (true) {
0738:                        start = reader.mark();
0739:                        stop = reader.skipUntil("<");
0740:                        if (stop == null) {
0741:                            err.jspError(start, "jsp.error.unterminated",
0742:                                    "&lt;jsp:expression&gt;");
0743:                        }
0744:                        text = parseScriptText(reader.getText(start, stop));
0745:                        new Node.Expression(text, start, parent);
0746:                        if (reader.matches("![CDATA[")) {
0747:                            start = reader.mark();
0748:                            stop = reader.skipUntil("]]>");
0749:                            if (stop == null) {
0750:                                err.jspError(start, "jsp.error.unterminated",
0751:                                        "CDATA");
0752:                            }
0753:                            text = parseScriptText(reader.getText(start, stop));
0754:                            new Node.Expression(text, start, parent);
0755:                        } else {
0756:                            break;
0757:                        }
0758:                    }
0759:                    if (!reader.matchesETagWithoutLessThan("jsp:expression")) {
0760:                        err.jspError(start, "jsp.error.unterminated",
0761:                                "&lt;jsp:expression&gt;");
0762:                    }
0763:                }
0764:            }
0765:
0766:            /*
0767:             * ELExpressionBody
0768:             * (following "${" to first unquoted "}")
0769:             * // XXX add formal production and confirm implementation against it,
0770:             * //     once it's decided
0771:             */
0772:            private void parseELExpression(Node parent) throws JasperException {
0773:                start = reader.mark();
0774:                Mark last = null;
0775:                boolean singleQuoted = false, doubleQuoted = false;
0776:                int currentChar;
0777:                do {
0778:                    // XXX could move this logic to JspReader
0779:                    last = reader.mark(); // XXX somewhat wasteful
0780:                    currentChar = reader.nextChar();
0781:                    if (currentChar == '\\' && (singleQuoted || doubleQuoted)) {
0782:                        // skip character following '\' within quotes
0783:                        reader.nextChar();
0784:                        currentChar = reader.nextChar();
0785:                    }
0786:                    if (currentChar == -1)
0787:                        err.jspError(start, "jsp.error.unterminated", "${");
0788:                    if (currentChar == '"')
0789:                        doubleQuoted = !doubleQuoted;
0790:                    if (currentChar == '\'')
0791:                        singleQuoted = !singleQuoted;
0792:                } while (currentChar != '}' || (singleQuoted || doubleQuoted));
0793:
0794:                new Node.ELExpression(reader.getText(start, last), start,
0795:                        parent);
0796:            }
0797:
0798:            /*
0799:             * ScriptletBody ::= (Char* - (char* '%>')) '%>'
0800:             */
0801:            private void parseScriptlet(Node parent) throws JasperException {
0802:                start = reader.mark();
0803:                Mark stop = reader.skipUntil("%>");
0804:                if (stop == null) {
0805:                    err.jspError(start, "jsp.error.unterminated", "&lt;%");
0806:                }
0807:
0808:                new Node.Scriptlet(
0809:                        parseScriptText(reader.getText(start, stop)), start,
0810:                        parent);
0811:            }
0812:
0813:            /*
0814:             * XMLScriptletBody ::=   ( S? '/>' )
0815:             *                      | ( S? '>' (Char* - (char* '<')) CDSect?)* ETag )
0816:             *                      | <TRANSLATION_ERROR>
0817:             */
0818:            private void parseXMLScriptlet(Node parent) throws JasperException {
0819:                reader.skipSpaces();
0820:                if (!reader.matches("/>")) {
0821:                    if (!reader.matches(">")) {
0822:                        err.jspError(start, "jsp.error.unterminated",
0823:                                "&lt;jsp:scriptlet&gt;");
0824:                    }
0825:                    Mark stop;
0826:                    String text;
0827:                    while (true) {
0828:                        start = reader.mark();
0829:                        stop = reader.skipUntil("<");
0830:                        if (stop == null) {
0831:                            err.jspError(start, "jsp.error.unterminated",
0832:                                    "&lt;jsp:scriptlet&gt;");
0833:                        }
0834:                        text = parseScriptText(reader.getText(start, stop));
0835:                        new Node.Scriptlet(text, start, parent);
0836:                        if (reader.matches("![CDATA[")) {
0837:                            start = reader.mark();
0838:                            stop = reader.skipUntil("]]>");
0839:                            if (stop == null) {
0840:                                err.jspError(start, "jsp.error.unterminated",
0841:                                        "CDATA");
0842:                            }
0843:                            text = parseScriptText(reader.getText(start, stop));
0844:                            new Node.Scriptlet(text, start, parent);
0845:                        } else {
0846:                            break;
0847:                        }
0848:                    }
0849:
0850:                    if (!reader.matchesETagWithoutLessThan("jsp:scriptlet")) {
0851:                        err.jspError(start, "jsp.error.unterminated",
0852:                                "&lt;jsp:scriptlet&gt;");
0853:                    }
0854:                }
0855:            }
0856:
0857:            /**
0858:             * Param ::= '<jsp:param' S Attributes S? EmptyBody S?
0859:             */
0860:            private void parseParam(Node parent) throws JasperException {
0861:                if (!reader.matches("<jsp:param")) {
0862:                    err.jspError(reader.mark(), "jsp.error.paramexpected");
0863:                }
0864:                Attributes attrs = parseAttributes();
0865:                reader.skipSpaces();
0866:
0867:                Node paramActionNode = new Node.ParamAction(attrs, start,
0868:                        parent);
0869:
0870:                parseEmptyBody(paramActionNode, "jsp:param");
0871:
0872:                reader.skipSpaces();
0873:            }
0874:
0875:            /*
0876:             * For Include:
0877:             * StdActionContent ::= Attributes ParamBody
0878:             *
0879:             * ParamBody ::=   EmptyBody
0880:             *               | ( '>' S? ( '<jsp:attribute' NamedAttributes )?
0881:             *                   '<jsp:body'
0882:             *                   (JspBodyParam | <TRANSLATION_ERROR> )
0883:             *                   S? ETag
0884:             *                 )
0885:             *               | ( '>' S? Param* ETag )
0886:             *
0887:             * EmptyBody ::=   '/>'
0888:             *               | ( '>' ETag )
0889:             *               | ( '>' S? '<jsp:attribute' NamedAttributes ETag )
0890:             *
0891:             * JspBodyParam ::= S? '>' Param* '</jsp:body>'
0892:             */
0893:            private void parseInclude(Node parent) throws JasperException {
0894:                Attributes attrs = parseAttributes();
0895:                reader.skipSpaces();
0896:
0897:                Node includeNode = new Node.IncludeAction(attrs, start, parent);
0898:
0899:                parseOptionalBody(includeNode, "jsp:include",
0900:                        JAVAX_BODY_CONTENT_PARAM);
0901:            }
0902:
0903:            /*
0904:             * For Forward:
0905:             * StdActionContent ::= Attributes ParamBody
0906:             */
0907:            private void parseForward(Node parent) throws JasperException {
0908:                Attributes attrs = parseAttributes();
0909:                reader.skipSpaces();
0910:
0911:                Node forwardNode = new Node.ForwardAction(attrs, start, parent);
0912:
0913:                parseOptionalBody(forwardNode, "jsp:forward",
0914:                        JAVAX_BODY_CONTENT_PARAM);
0915:            }
0916:
0917:            private void parseInvoke(Node parent) throws JasperException {
0918:                Attributes attrs = parseAttributes();
0919:                reader.skipSpaces();
0920:
0921:                Node invokeNode = new Node.InvokeAction(attrs, start, parent);
0922:
0923:                parseEmptyBody(invokeNode, "jsp:invoke");
0924:            }
0925:
0926:            private void parseDoBody(Node parent) throws JasperException {
0927:                Attributes attrs = parseAttributes();
0928:                reader.skipSpaces();
0929:
0930:                Node doBodyNode = new Node.DoBodyAction(attrs, start, parent);
0931:
0932:                parseEmptyBody(doBodyNode, "jsp:doBody");
0933:            }
0934:
0935:            private void parseElement(Node parent) throws JasperException {
0936:                Attributes attrs = parseAttributes();
0937:                reader.skipSpaces();
0938:
0939:                Node elementNode = new Node.JspElement(attrs, start, parent);
0940:
0941:                parseOptionalBody(elementNode, "jsp:element",
0942:                        TagInfo.BODY_CONTENT_JSP);
0943:            }
0944:
0945:            /*
0946:             * For GetProperty:
0947:             * StdActionContent ::= Attributes EmptyBody
0948:             */
0949:            private void parseGetProperty(Node parent) throws JasperException {
0950:                Attributes attrs = parseAttributes();
0951:                reader.skipSpaces();
0952:
0953:                Node getPropertyNode = new Node.GetProperty(attrs, start,
0954:                        parent);
0955:
0956:                parseOptionalBody(getPropertyNode, "jsp:getProperty",
0957:                        TagInfo.BODY_CONTENT_EMPTY);
0958:            }
0959:
0960:            /*
0961:             * For SetProperty:
0962:             * StdActionContent ::= Attributes EmptyBody
0963:             */
0964:            private void parseSetProperty(Node parent) throws JasperException {
0965:                Attributes attrs = parseAttributes();
0966:                reader.skipSpaces();
0967:
0968:                Node setPropertyNode = new Node.SetProperty(attrs, start,
0969:                        parent);
0970:
0971:                parseOptionalBody(setPropertyNode, "jsp:setProperty",
0972:                        TagInfo.BODY_CONTENT_EMPTY);
0973:            }
0974:
0975:            /*
0976:             * EmptyBody ::=   '/>'
0977:             *               | ( '>' ETag )
0978:             *               | ( '>' S? '<jsp:attribute' NamedAttributes ETag )
0979:             */
0980:            private void parseEmptyBody(Node parent, String tag)
0981:                    throws JasperException {
0982:                if (reader.matches("/>")) {
0983:                    // Done
0984:                } else if (reader.matches(">")) {
0985:                    if (reader.matchesETag(tag)) {
0986:                        // Done
0987:                    } else if (reader
0988:                            .matchesOptionalSpacesFollowedBy("<jsp:attribute")) {
0989:                        // Parse the one or more named attribute nodes
0990:                        parseNamedAttributes(parent);
0991:                        if (!reader.matchesETag(tag)) {
0992:                            // Body not allowed
0993:                            err.jspError(reader.mark(),
0994:                                    "jsp.error.jspbody.emptybody.only", "&lt;"
0995:                                            + tag);
0996:                        }
0997:                    } else {
0998:                        err.jspError(reader.mark(),
0999:                                "jsp.error.jspbody.emptybody.only", "&lt;"
1000:                                        + tag);
1001:                    }
1002:                } else {
1003:                    err.jspError(reader.mark(), "jsp.error.unterminated",
1004:                            "&lt;" + tag);
1005:                }
1006:            }
1007:
1008:            /*
1009:             * For UseBean:
1010:             * StdActionContent ::= Attributes OptionalBody
1011:             */
1012:            private void parseUseBean(Node parent) throws JasperException {
1013:                Attributes attrs = parseAttributes();
1014:                reader.skipSpaces();
1015:
1016:                Node useBeanNode = new Node.UseBean(attrs, start, parent);
1017:
1018:                parseOptionalBody(useBeanNode, "jsp:useBean",
1019:                        TagInfo.BODY_CONTENT_JSP);
1020:            }
1021:
1022:            /*
1023:             * Parses OptionalBody, but also reused to parse bodies for plugin
1024:             * and param since the syntax is identical (the only thing that
1025:             * differs substantially is how to process the body, and thus
1026:             * we accept the body type as a parameter).
1027:             *
1028:             * OptionalBody ::= EmptyBody | ActionBody
1029:             *
1030:             * ScriptlessOptionalBody ::= EmptyBody | ScriptlessActionBody
1031:             *
1032:             * TagDependentOptionalBody ::= EmptyBody | TagDependentActionBody
1033:             *
1034:             * EmptyBody ::=   '/>'
1035:             *               | ( '>' ETag )
1036:             *               | ( '>' S? '<jsp:attribute' NamedAttributes ETag )
1037:             *
1038:             * ActionBody ::=   JspAttributeAndBody
1039:             *                | ( '>' Body ETag )
1040:             *
1041:             * ScriptlessActionBody ::=   JspAttributeAndBody 
1042:             *                          | ( '>' ScriptlessBody ETag )
1043:             * 
1044:             * TagDependentActionBody ::=   JspAttributeAndBody
1045:             *                            | ( '>' TagDependentBody ETag )
1046:             *
1047:             */
1048:            private void parseOptionalBody(Node parent, String tag,
1049:                    String bodyType) throws JasperException {
1050:                if (reader.matches("/>")) {
1051:                    // EmptyBody
1052:                    return;
1053:                }
1054:
1055:                if (!reader.matches(">")) {
1056:                    err.jspError(reader.mark(), "jsp.error.unterminated",
1057:                            "&lt;" + tag);
1058:                }
1059:
1060:                if (reader.matchesETag(tag)) {
1061:                    // EmptyBody
1062:                    return;
1063:                }
1064:
1065:                if (!parseJspAttributeAndBody(parent, tag, bodyType)) {
1066:                    // Must be ( '>' # Body ETag )
1067:                    parseBody(parent, tag, bodyType);
1068:                }
1069:            }
1070:
1071:            /**
1072:             * Attempts to parse 'JspAttributeAndBody' production.  Returns true if
1073:             * it matched, or false if not.  Assumes EmptyBody is okay as well.
1074:             *
1075:             * JspAttributeAndBody ::=
1076:             *                  ( '>' # S? ( '<jsp:attribute' NamedAttributes )?
1077:             *                    '<jsp:body'
1078:             *                    ( JspBodyBody | <TRANSLATION_ERROR> )
1079:             *                    S? ETag
1080:             *                  )
1081:             */
1082:            private boolean parseJspAttributeAndBody(Node parent, String tag,
1083:                    String bodyType) throws JasperException {
1084:                boolean result = false;
1085:
1086:                if (reader.matchesOptionalSpacesFollowedBy("<jsp:attribute")) {
1087:                    // May be an EmptyBody, depending on whether
1088:                    // There's a "<jsp:body" before the ETag
1089:
1090:                    // First, parse <jsp:attribute> elements:
1091:                    parseNamedAttributes(parent);
1092:
1093:                    result = true;
1094:                }
1095:
1096:                if (reader.matchesOptionalSpacesFollowedBy("<jsp:body")) {
1097:                    // ActionBody
1098:                    parseJspBody(parent, bodyType);
1099:                    reader.skipSpaces();
1100:                    if (!reader.matchesETag(tag)) {
1101:                        err.jspError(reader.mark(), "jsp.error.unterminated",
1102:                                "&lt;" + tag);
1103:                    }
1104:
1105:                    result = true;
1106:                } else if (result && !reader.matchesETag(tag)) {
1107:                    // If we have <jsp:attribute> but something other than
1108:                    // <jsp:body> or the end tag, translation error.
1109:                    err.jspError(reader.mark(), "jsp.error.jspbody.required",
1110:                            "&lt;" + tag);
1111:                }
1112:
1113:                return result;
1114:            }
1115:
1116:            /*
1117:             * Params ::=  `>' S?
1118:             *              (   ( `<jsp:body>'
1119:             *                    ( ( S? Param+ S? `</jsp:body>' )
1120:             *                      | <TRANSLATION_ERROR>
1121:             *                    )
1122:             *                  )
1123:             *                | Param+
1124:             *              )
1125:             *              '</jsp:params>'
1126:             */
1127:            private void parseJspParams(Node parent) throws JasperException {
1128:                Node jspParamsNode = new Node.ParamsAction(start, parent);
1129:                parseOptionalBody(jspParamsNode, "jsp:params",
1130:                        JAVAX_BODY_CONTENT_PARAM);
1131:            }
1132:
1133:            /*
1134:             * Fallback ::=   '/>'
1135:             *               | ( `>' S? `<jsp:body>'
1136:             *                   (   ( S?
1137:             *                         ( Char* - ( Char* `</jsp:body>' ) )
1138:             *                         `</jsp:body>' S?
1139:             *                       )
1140:             *                     | <TRANSLATION_ERROR>
1141:             *                   )
1142:             *                   `</jsp:fallback>'
1143:             *                 )
1144:             *               | ( '>'
1145:             *                   ( Char* - ( Char* '</jsp:fallback>' ) )
1146:             *                   '</jsp:fallback>'
1147:             *                 )
1148:             */
1149:            private void parseFallBack(Node parent) throws JasperException {
1150:                Node fallBackNode = new Node.FallBackAction(start, parent);
1151:                parseOptionalBody(fallBackNode, "jsp:fallback",
1152:                        JAVAX_BODY_CONTENT_TEMPLATE_TEXT);
1153:            }
1154:
1155:            /*
1156:             * For Plugin:
1157:             * StdActionContent ::= Attributes PluginBody
1158:             *
1159:             * PluginBody ::=   EmptyBody 
1160:             *                | ( '>' S? ( '<jsp:attribute' NamedAttributes )?
1161:             *                    '<jsp:body'
1162:             *                    ( JspBodyPluginTags | <TRANSLATION_ERROR> )
1163:             *                    S? ETag
1164:             *                  )
1165:             *                | ( '>' S? PluginTags ETag )
1166:             *
1167:             * EmptyBody ::=   '/>'
1168:             *               | ( '>' ETag )
1169:             *               | ( '>' S? '<jsp:attribute' NamedAttributes ETag )
1170:             *
1171:             */
1172:            private void parsePlugin(Node parent) throws JasperException {
1173:                Attributes attrs = parseAttributes();
1174:                reader.skipSpaces();
1175:
1176:                Node pluginNode = new Node.PlugIn(attrs, start, parent);
1177:
1178:                parseOptionalBody(pluginNode, "jsp:plugin",
1179:                        JAVAX_BODY_CONTENT_PLUGIN);
1180:            }
1181:
1182:            /*
1183:             * PluginTags ::= ( '<jsp:params' Params S? )?
1184:             *                ( '<jsp:fallback' Fallback? S? )?
1185:             */
1186:            private void parsePluginTags(Node parent) throws JasperException {
1187:                reader.skipSpaces();
1188:
1189:                if (reader.matches("<jsp:params")) {
1190:                    parseJspParams(parent);
1191:                    reader.skipSpaces();
1192:                }
1193:
1194:                if (reader.matches("<jsp:fallback")) {
1195:                    parseFallBack(parent);
1196:                    reader.skipSpaces();
1197:                }
1198:            }
1199:
1200:            /*
1201:             * StandardAction ::=   'include'       StdActionContent
1202:             *                    | 'forward'       StdActionContent
1203:             *                    | 'invoke'        StdActionContent
1204:             *                    | 'doBody'        StdActionContent
1205:             *                    | 'getProperty'   StdActionContent
1206:             *                    | 'setProperty'   StdActionContent
1207:             *                    | 'useBean'       StdActionContent
1208:             *                    | 'plugin'        StdActionContent
1209:             *                    | 'element'       StdActionContent
1210:             */
1211:            private void parseStandardAction(Node parent)
1212:                    throws JasperException {
1213:                Mark start = reader.mark();
1214:
1215:                if (reader.matches(INCLUDE_ACTION)) {
1216:                    parseInclude(parent);
1217:                } else if (reader.matches(FORWARD_ACTION)) {
1218:                    parseForward(parent);
1219:                } else if (reader.matches(INVOKE_ACTION)) {
1220:                    if (!isTagFile) {
1221:                        err.jspError(reader.mark(),
1222:                                "jsp.error.action.isnottagfile",
1223:                                "&lt;jsp:invoke");
1224:                    }
1225:                    parseInvoke(parent);
1226:                } else if (reader.matches(DOBODY_ACTION)) {
1227:                    if (!isTagFile) {
1228:                        err.jspError(reader.mark(),
1229:                                "jsp.error.action.isnottagfile",
1230:                                "&lt;jsp:doBody");
1231:                    }
1232:                    parseDoBody(parent);
1233:                } else if (reader.matches(GET_PROPERTY_ACTION)) {
1234:                    parseGetProperty(parent);
1235:                } else if (reader.matches(SET_PROPERTY_ACTION)) {
1236:                    parseSetProperty(parent);
1237:                } else if (reader.matches(USE_BEAN_ACTION)) {
1238:                    parseUseBean(parent);
1239:                } else if (reader.matches(PLUGIN_ACTION)) {
1240:                    parsePlugin(parent);
1241:                } else if (reader.matches(ELEMENT_ACTION)) {
1242:                    parseElement(parent);
1243:                } else if (reader.matches(ATTRIBUTE_ACTION)) {
1244:                    err.jspError(start, "jsp.error.namedAttribute.invalidUse");
1245:                } else if (reader.matches(BODY_ACTION)) {
1246:                    err.jspError(start, "jsp.error.jspbody.invalidUse");
1247:                } else if (reader.matches(FALLBACK_ACTION)) {
1248:                    err.jspError(start, "jsp.error.fallback.invalidUse");
1249:                } else if (reader.matches(PARAMS_ACTION)) {
1250:                    err.jspError(start, "jsp.error.params.invalidUse");
1251:                } else if (reader.matches(PARAM_ACTION)) {
1252:                    err.jspError(start, "jsp.error.param.invalidUse");
1253:                } else if (reader.matches(OUTPUT_ACTION)) {
1254:                    err.jspError(start, "jsp.error.jspoutput.invalidUse");
1255:                } else {
1256:                    err.jspError(start, "jsp.error.badStandardAction");
1257:                }
1258:            }
1259:
1260:            /*
1261:             * # '<' CustomAction CustomActionBody
1262:             *
1263:             * CustomAction ::= TagPrefix ':' CustomActionName
1264:             *
1265:             * TagPrefix ::= Name
1266:             *
1267:             * CustomActionName ::= Name
1268:             *
1269:             * CustomActionBody ::=   ( Attributes CustomActionEnd )
1270:             *                      | <TRANSLATION_ERROR>
1271:             *
1272:             * Attributes ::= ( S Attribute )* S?
1273:             *
1274:             * CustomActionEnd ::=   CustomActionTagDependent
1275:             *                     | CustomActionJSPContent
1276:             *                     | CustomActionScriptlessContent
1277:             *
1278:             * CustomActionTagDependent ::= TagDependentOptionalBody
1279:             *
1280:             * CustomActionJSPContent ::= OptionalBody
1281:             *
1282:             * CustomActionScriptlessContent ::= ScriptlessOptionalBody
1283:             */
1284:            private boolean parseCustomTag(Node parent) throws JasperException {
1285:
1286:                if (reader.peekChar() != '<') {
1287:                    return false;
1288:                }
1289:
1290:                // Parse 'CustomAction' production (tag prefix and custom action name)
1291:                reader.nextChar(); // skip '<'
1292:                String tagName = reader.parseToken(false);
1293:                int i = tagName.indexOf(':');
1294:                if (i == -1) {
1295:                    reader.reset(start);
1296:                    return false;
1297:                }
1298:
1299:                String prefix = tagName.substring(0, i);
1300:                String shortTagName = tagName.substring(i + 1);
1301:
1302:                // Check if this is a user-defined tag.
1303:                String uri = pageInfo.getURI(prefix);
1304:                if (uri == null) {
1305:                    reader.reset(start);
1306:                    // Remember the prefix for later error checking
1307:                    pageInfo.putNonCustomTagPrefix(prefix, reader.mark());
1308:                    return false;
1309:                }
1310:
1311:                TagLibraryInfo tagLibInfo = pageInfo.getTaglib(uri);
1312:                TagInfo tagInfo = tagLibInfo.getTag(shortTagName);
1313:                TagFileInfo tagFileInfo = tagLibInfo.getTagFile(shortTagName);
1314:                if (tagInfo == null && tagFileInfo == null) {
1315:                    err.jspError(start, "jsp.error.bad_tag", shortTagName,
1316:                            prefix);
1317:                }
1318:                Class tagHandlerClass = null;
1319:                if (tagInfo != null) {
1320:                    // Must be a classic tag, load it here.
1321:                    // tag files will be loaded later, in TagFileProcessor
1322:                    String handlerClassName = tagInfo.getTagClassName();
1323:                    try {
1324:                        tagHandlerClass = ctxt.getClassLoader().loadClass(
1325:                                handlerClassName);
1326:                    } catch (Exception e) {
1327:                        err.jspError(start, "jsp.error.loadclass.taghandler",
1328:                                handlerClassName, tagName);
1329:                    }
1330:                }
1331:
1332:                // Parse 'CustomActionBody' production:
1333:                // At this point we are committed - if anything fails, we produce
1334:                // a translation error.
1335:
1336:                // Parse 'Attributes' production:
1337:                Attributes attrs = parseAttributes();
1338:                reader.skipSpaces();
1339:
1340:                // Parse 'CustomActionEnd' production:
1341:                if (reader.matches("/>")) {
1342:                    if (tagInfo != null) {
1343:                        new Node.CustomTag(tagName, prefix, shortTagName, uri,
1344:                                attrs, start, parent, tagInfo, tagHandlerClass);
1345:                    } else {
1346:                        new Node.CustomTag(tagName, prefix, shortTagName, uri,
1347:                                attrs, start, parent, tagFileInfo);
1348:                    }
1349:                    return true;
1350:                }
1351:
1352:                // Now we parse one of 'CustomActionTagDependent', 
1353:                // 'CustomActionJSPContent', or 'CustomActionScriptlessContent'.
1354:                // depending on body-content in TLD.
1355:
1356:                // Looking for a body, it still can be empty; but if there is a
1357:                // a tag body, its syntax would be dependent on the type of
1358:                // body content declared in the TLD.
1359:                String bc;
1360:                if (tagInfo != null) {
1361:                    bc = tagInfo.getBodyContent();
1362:                } else {
1363:                    bc = tagFileInfo.getTagInfo().getBodyContent();
1364:                }
1365:
1366:                Node tagNode = null;
1367:                if (tagInfo != null) {
1368:                    tagNode = new Node.CustomTag(tagName, prefix, shortTagName,
1369:                            uri, attrs, start, parent, tagInfo, tagHandlerClass);
1370:                } else {
1371:                    tagNode = new Node.CustomTag(tagName, prefix, shortTagName,
1372:                            uri, attrs, start, parent, tagFileInfo);
1373:                }
1374:
1375:                parseOptionalBody(tagNode, tagName, bc);
1376:
1377:                return true;
1378:            }
1379:
1380:            /*
1381:             * Parse for a template text string until '<' or "${" is encountered, 
1382:             * recognizing escape sequences "\%" and "\$".
1383:             */
1384:            private void parseTemplateText(Node parent) throws JasperException {
1385:
1386:                if (!reader.hasMoreInput())
1387:                    return;
1388:
1389:                CharArrayWriter ttext = new CharArrayWriter();
1390:                // Output the first character
1391:                int ch = reader.nextChar();
1392:                ttext.write(ch);
1393:
1394:                while (reader.hasMoreInput()) {
1395:                    ch = reader.nextChar();
1396:                    if (ch == '<') {
1397:                        reader.pushChar();
1398:                        break;
1399:                    } else if (ch == '$') {
1400:                        if (!reader.hasMoreInput()) {
1401:                            ttext.write('$');
1402:                            break;
1403:                        }
1404:                        ch = reader.nextChar();
1405:                        if (ch == '{') {
1406:                            reader.pushChar();
1407:                            reader.pushChar();
1408:                            break;
1409:                        }
1410:                        ttext.write('$');
1411:                        reader.pushChar();
1412:                        continue;
1413:                    } else if (ch == '\\') {
1414:                        if (!reader.hasMoreInput()) {
1415:                            ttext.write('\\');
1416:                            break;
1417:                        }
1418:                        char next = (char) reader.peekChar();
1419:                        // Looking for \% or \$
1420:                        // TODO: only recognize \$ if isELIgnored is false, but since
1421:                        // it can be set in a page directive, it cannot be determined
1422:                        // here.  Argh!
1423:                        if (next == '%' || next == '$') {
1424:                            ch = reader.nextChar();
1425:                        }
1426:                    }
1427:                    ttext.write(ch);
1428:                }
1429:                new Node.TemplateText(ttext.toString(), start, parent);
1430:            }
1431:
1432:            /*
1433:             * XMLTemplateText ::=   ( S? '/>' )
1434:             *                     | ( S? '>'
1435:             *                         ( ( Char* - ( Char* ( '<' | '${' ) ) )
1436:             *                           ( '${' ELExpressionBody )?
1437:             *                           CDSect?
1438:             *                         )* ETag
1439:             *                       )
1440:             *                     | <TRANSLATION_ERROR>
1441:             */
1442:            private void parseXMLTemplateText(Node parent)
1443:                    throws JasperException {
1444:                reader.skipSpaces();
1445:                if (!reader.matches("/>")) {
1446:                    if (!reader.matches(">")) {
1447:                        err.jspError(start, "jsp.error.unterminated",
1448:                                "&lt;jsp:text&gt;");
1449:                    }
1450:                    CharArrayWriter ttext = new CharArrayWriter();
1451:                    while (reader.hasMoreInput()) {
1452:                        int ch = reader.nextChar();
1453:                        if (ch == '<') {
1454:                            // Check for <![CDATA[
1455:                            if (!reader.matches("![CDATA[")) {
1456:                                break;
1457:                            }
1458:                            start = reader.mark();
1459:                            Mark stop = reader.skipUntil("]]>");
1460:                            if (stop == null) {
1461:                                err.jspError(start, "jsp.error.unterminated",
1462:                                        "CDATA");
1463:                            }
1464:                            String text = reader.getText(start, stop);
1465:                            ttext.write(text, 0, text.length());
1466:                        } else if (ch == '\\') {
1467:                            if (!reader.hasMoreInput()) {
1468:                                ttext.write('\\');
1469:                                break;
1470:                            }
1471:                            ch = reader.nextChar();
1472:                            if (ch != '$') {
1473:                                ttext.write('\\');
1474:                            }
1475:                            ttext.write(ch);
1476:                        } else if (ch == '$') {
1477:                            if (!reader.hasMoreInput()) {
1478:                                ttext.write('$');
1479:                                break;
1480:                            }
1481:                            ch = reader.nextChar();
1482:                            if (ch != '{') {
1483:                                ttext.write('$');
1484:                                reader.pushChar();
1485:                                continue;
1486:                            }
1487:                            // Create a template text node
1488:                            new Node.TemplateText(ttext.toString(), start,
1489:                                    parent);
1490:
1491:                            // Mark and parse the EL expression and create its node:
1492:                            start = reader.mark();
1493:                            parseELExpression(parent);
1494:
1495:                            start = reader.mark();
1496:                            ttext = new CharArrayWriter();
1497:                        } else {
1498:                            ttext.write(ch);
1499:                        }
1500:                    }
1501:
1502:                    new Node.TemplateText(ttext.toString(), start, parent);
1503:
1504:                    if (!reader.hasMoreInput()) {
1505:                        err.jspError(start, "jsp.error.unterminated",
1506:                                "&lt;jsp:text&gt;");
1507:                    } else if (!reader.matchesETagWithoutLessThan("jsp:text")) {
1508:                        err.jspError(start, "jsp.error.jsptext.badcontent");
1509:                    }
1510:                }
1511:            }
1512:
1513:            /*
1514:             * AllBody ::=       ( '<%--'              JSPCommentBody     )
1515:             *                 | ( '<%@'               DirectiveBody      )
1516:             *                 | ( '<jsp:directive.'   XMLDirectiveBody   )
1517:             *                 | ( '<%!'               DeclarationBody    )
1518:             *                 | ( '<jsp:declaration'  XMLDeclarationBody )
1519:             *                 | ( '<%='               ExpressionBody     )
1520:             *                 | ( '<jsp:expression'   XMLExpressionBody  )
1521:             *                 | ( '${'                ELExpressionBody   )
1522:             *                 | ( '<%'                ScriptletBody      )
1523:             *                 | ( '<jsp:scriptlet'    XMLScriptletBody   )
1524:             *                 | ( '<jsp:text'         XMLTemplateText    )
1525:             *                 | ( '<jsp:'             StandardAction     )
1526:             *                 | ( '<'                 CustomAction
1527:             *                                         CustomActionBody   )
1528:             *	               | TemplateText
1529:             */
1530:            private void parseElements(Node parent) throws JasperException {
1531:                if (scriptlessCount > 0) {
1532:                    // vc: ScriptlessBody
1533:                    // We must follow the ScriptlessBody production if one of
1534:                    // our parents is ScriptlessBody.
1535:                    parseElementsScriptless(parent);
1536:                    return;
1537:                }
1538:
1539:                start = reader.mark();
1540:                if (reader.matches("<%--")) {
1541:                    parseComment(parent);
1542:                } else if (reader.matches("<%@")) {
1543:                    parseDirective(parent);
1544:                } else if (reader.matches("<jsp:directive.")) {
1545:                    parseXMLDirective(parent);
1546:                } else if (reader.matches("<%!")) {
1547:                    parseDeclaration(parent);
1548:                } else if (reader.matches("<jsp:declaration")) {
1549:                    parseXMLDeclaration(parent);
1550:                } else if (reader.matches("<%=")) {
1551:                    parseExpression(parent);
1552:                } else if (reader.matches("<jsp:expression")) {
1553:                    parseXMLExpression(parent);
1554:                } else if (reader.matches("<%")) {
1555:                    parseScriptlet(parent);
1556:                } else if (reader.matches("<jsp:scriptlet")) {
1557:                    parseXMLScriptlet(parent);
1558:                } else if (reader.matches("<jsp:text")) {
1559:                    parseXMLTemplateText(parent);
1560:                } else if (reader.matches("${")) {
1561:                    parseELExpression(parent);
1562:                } else if (reader.matches("<jsp:")) {
1563:                    parseStandardAction(parent);
1564:                } else if (!parseCustomTag(parent)) {
1565:                    checkUnbalancedEndTag();
1566:                    parseTemplateText(parent);
1567:                }
1568:            }
1569:
1570:            /*
1571:             * ScriptlessBody ::=  ( '<%--'              JSPCommentBody      )
1572:             *                   | ( '<%@'               DirectiveBody       )
1573:             *                   | ( '<jsp:directive.'   XMLDirectiveBody    )
1574:             *                   | ( '<%!'               <TRANSLATION_ERROR> )
1575:             *                   | ( '<jsp:declaration'  <TRANSLATION_ERROR> )
1576:             *                   | ( '<%='               <TRANSLATION_ERROR> )
1577:             *                   | ( '<jsp:expression'   <TRANSLATION_ERROR> )
1578:             *                   | ( '<%'                <TRANSLATION_ERROR> )
1579:             *                   | ( '<jsp:scriptlet'    <TRANSLATION_ERROR> )
1580:             *                   | ( '<jsp:text'         XMLTemplateText     )
1581:             *                   | ( '${'                ELExpressionBody    )
1582:             *                   | ( '<jsp:'             StandardAction      )
1583:             *                   | ( '<'                 CustomAction
1584:             *                                           CustomActionBody    )
1585:             *                   | TemplateText
1586:             */
1587:            private void parseElementsScriptless(Node parent)
1588:                    throws JasperException {
1589:                // Keep track of how many scriptless nodes we've encountered
1590:                // so we know whether our child nodes are forced scriptless
1591:                scriptlessCount++;
1592:
1593:                start = reader.mark();
1594:                if (reader.matches("<%--")) {
1595:                    parseComment(parent);
1596:                } else if (reader.matches("<%@")) {
1597:                    parseDirective(parent);
1598:                } else if (reader.matches("<jsp:directive.")) {
1599:                    parseXMLDirective(parent);
1600:                } else if (reader.matches("<%!")) {
1601:                    err.jspError(reader.mark(), "jsp.error.no.scriptlets");
1602:                } else if (reader.matches("<jsp:declaration")) {
1603:                    err.jspError(reader.mark(), "jsp.error.no.scriptlets");
1604:                } else if (reader.matches("<%=")) {
1605:                    err.jspError(reader.mark(), "jsp.error.no.scriptlets");
1606:                } else if (reader.matches("<jsp:expression")) {
1607:                    err.jspError(reader.mark(), "jsp.error.no.scriptlets");
1608:                } else if (reader.matches("<%")) {
1609:                    err.jspError(reader.mark(), "jsp.error.no.scriptlets");
1610:                } else if (reader.matches("<jsp:scriptlet")) {
1611:                    err.jspError(reader.mark(), "jsp.error.no.scriptlets");
1612:                } else if (reader.matches("<jsp:text")) {
1613:                    parseXMLTemplateText(parent);
1614:                } else if (reader.matches("${")) {
1615:                    parseELExpression(parent);
1616:                } else if (reader.matches("<jsp:")) {
1617:                    parseStandardAction(parent);
1618:                } else if (!parseCustomTag(parent)) {
1619:                    checkUnbalancedEndTag();
1620:                    parseTemplateText(parent);
1621:                }
1622:
1623:                scriptlessCount--;
1624:            }
1625:
1626:            /*
1627:             * TemplateTextBody ::=   ( '<%--'              JSPCommentBody      )
1628:             *                      | ( '<%@'               DirectiveBody       )
1629:             *                      | ( '<jsp:directive.'   XMLDirectiveBody    )
1630:             *                      | ( '<%!'               <TRANSLATION_ERROR> )
1631:             *                      | ( '<jsp:declaration'  <TRANSLATION_ERROR> )
1632:             *                      | ( '<%='               <TRANSLATION_ERROR> )
1633:             *                      | ( '<jsp:expression'   <TRANSLATION_ERROR> )
1634:             *                      | ( '<%'                <TRANSLATION_ERROR> )
1635:             *                      | ( '<jsp:scriptlet'    <TRANSLATION_ERROR> )
1636:             *                      | ( '<jsp:text'         <TRANSLATION_ERROR> )
1637:             *                      | ( '${'                <TRANSLATION_ERROR> )
1638:             *                      | ( '<jsp:'             <TRANSLATION_ERROR> )
1639:             *                      | TemplateText
1640:             */
1641:            private void parseElementsTemplateText(Node parent)
1642:                    throws JasperException {
1643:                start = reader.mark();
1644:                if (reader.matches("<%--")) {
1645:                    parseComment(parent);
1646:                } else if (reader.matches("<%@")) {
1647:                    parseDirective(parent);
1648:                } else if (reader.matches("<jsp:directive.")) {
1649:                    parseXMLDirective(parent);
1650:                } else if (reader.matches("<%!")) {
1651:                    err.jspError(reader.mark(), "jsp.error.not.in.template",
1652:                            "Declarations");
1653:                } else if (reader.matches("<jsp:declaration")) {
1654:                    err.jspError(reader.mark(), "jsp.error.not.in.template",
1655:                            "Declarations");
1656:                } else if (reader.matches("<%=")) {
1657:                    err.jspError(reader.mark(), "jsp.error.not.in.template",
1658:                            "Expressions");
1659:                } else if (reader.matches("<jsp:expression")) {
1660:                    err.jspError(reader.mark(), "jsp.error.not.in.template",
1661:                            "Expressions");
1662:                } else if (reader.matches("<%")) {
1663:                    err.jspError(reader.mark(), "jsp.error.not.in.template",
1664:                            "Scriptlets");
1665:                } else if (reader.matches("<jsp:scriptlet")) {
1666:                    err.jspError(reader.mark(), "jsp.error.not.in.template",
1667:                            "Scriptlets");
1668:                } else if (reader.matches("<jsp:text")) {
1669:                    err.jspError(reader.mark(), "jsp.error.not.in.template",
1670:                            "&lt;jsp:text");
1671:                } else if (reader.matches("${")) {
1672:                    err.jspError(reader.mark(), "jsp.error.not.in.template",
1673:                            "Expression language");
1674:                } else if (reader.matches("<jsp:")) {
1675:                    err.jspError(reader.mark(), "jsp.error.not.in.template",
1676:                            "Standard actions");
1677:                } else if (parseCustomTag(parent)) {
1678:                    err.jspError(reader.mark(), "jsp.error.not.in.template",
1679:                            "Custom actions");
1680:                } else {
1681:                    checkUnbalancedEndTag();
1682:                    parseTemplateText(parent);
1683:                }
1684:            }
1685:
1686:            /*
1687:             * Flag as error if an unbalanced end tag appears by itself.
1688:             */
1689:            private void checkUnbalancedEndTag() throws JasperException {
1690:
1691:                if (!reader.matches("</")) {
1692:                    return;
1693:                }
1694:
1695:                // Check for unbalanced standard actions
1696:                if (reader.matches("jsp:")) {
1697:                    err.jspError(start, "jsp.error.unbalanced.endtag", "jsp:");
1698:                }
1699:
1700:                // Check for unbalanced custom actions
1701:                String tagName = reader.parseToken(false);
1702:                int i = tagName.indexOf(':');
1703:                if (i == -1 || pageInfo.getURI(tagName.substring(0, i)) == null) {
1704:                    reader.reset(start);
1705:                    return;
1706:                }
1707:
1708:                err.jspError(start, "jsp.error.unbalanced.endtag", tagName);
1709:            }
1710:
1711:            /**
1712:             * TagDependentBody := 
1713:             */
1714:            private void parseTagDependentBody(Node parent, String tag)
1715:                    throws JasperException {
1716:                Mark bodyStart = reader.mark();
1717:                Mark bodyEnd = reader.skipUntilETag(tag);
1718:                if (bodyEnd == null) {
1719:                    err.jspError(start, "jsp.error.unterminated", "&lt;" + tag);
1720:                }
1721:                new Node.TemplateText(reader.getText(bodyStart, bodyEnd),
1722:                        bodyStart, parent);
1723:            }
1724:
1725:            /*
1726:             * Parses jsp:body action.
1727:             */
1728:            private void parseJspBody(Node parent, String bodyType)
1729:                    throws JasperException {
1730:                Mark start = reader.mark();
1731:                Node bodyNode = new Node.JspBody(start, parent);
1732:
1733:                reader.skipSpaces();
1734:                if (!reader.matches("/>")) {
1735:                    if (!reader.matches(">")) {
1736:                        err.jspError(start, "jsp.error.unterminated",
1737:                                "&lt;jsp:body");
1738:                    }
1739:                    parseBody(bodyNode, "jsp:body", bodyType);
1740:                }
1741:            }
1742:
1743:            /*
1744:             * Parse the body as JSP content.
1745:             * @param tag The name of the tag whose end tag would terminate the body
1746:             * @param bodyType One of the TagInfo body types
1747:             */
1748:            private void parseBody(Node parent, String tag, String bodyType)
1749:                    throws JasperException {
1750:                if (bodyType
1751:                        .equalsIgnoreCase(TagInfo.BODY_CONTENT_TAG_DEPENDENT)) {
1752:                    parseTagDependentBody(parent, tag);
1753:                } else if (bodyType
1754:                        .equalsIgnoreCase(TagInfo.BODY_CONTENT_EMPTY)) {
1755:                    if (!reader.matchesETag(tag)) {
1756:                        err.jspError(start,
1757:                                "jasper.error.emptybodycontent.nonempty", tag);
1758:                    }
1759:                } else if (bodyType == JAVAX_BODY_CONTENT_PLUGIN) {
1760:                    // (note the == since we won't recognize JAVAX_* 
1761:                    // from outside this module).
1762:                    parsePluginTags(parent);
1763:                    if (!reader.matchesETag(tag)) {
1764:                        err.jspError(reader.mark(), "jsp.error.unterminated",
1765:                                "&lt;" + tag);
1766:                    }
1767:                } else if (bodyType.equalsIgnoreCase(TagInfo.BODY_CONTENT_JSP)
1768:                        || bodyType
1769:                                .equalsIgnoreCase(TagInfo.BODY_CONTENT_SCRIPTLESS)
1770:                        || (bodyType == JAVAX_BODY_CONTENT_PARAM)
1771:                        || (bodyType == JAVAX_BODY_CONTENT_TEMPLATE_TEXT)) {
1772:                    while (reader.hasMoreInput()) {
1773:                        if (reader.matchesETag(tag)) {
1774:                            return;
1775:                        }
1776:
1777:                        // Check for nested jsp:body or jsp:attribute
1778:                        if (tag.equals("jsp:body")
1779:                                || tag.equals("jsp:attribute")) {
1780:                            if (reader.matches("<jsp:attribute")) {
1781:                                err.jspError(reader.mark(),
1782:                                        "jsp.error.nested.jspattribute");
1783:                            } else if (reader.matches("<jsp:body")) {
1784:                                err.jspError(reader.mark(),
1785:                                        "jsp.error.nested.jspbody");
1786:                            }
1787:                        }
1788:
1789:                        if (bodyType.equalsIgnoreCase(TagInfo.BODY_CONTENT_JSP)) {
1790:                            parseElements(parent);
1791:                        } else if (bodyType
1792:                                .equalsIgnoreCase(TagInfo.BODY_CONTENT_SCRIPTLESS)) {
1793:                            parseElementsScriptless(parent);
1794:                        } else if (bodyType == JAVAX_BODY_CONTENT_PARAM) {
1795:                            // (note the == since we won't recognize JAVAX_* 
1796:                            // from outside this module).
1797:                            reader.skipSpaces();
1798:                            parseParam(parent);
1799:                        } else if (bodyType == JAVAX_BODY_CONTENT_TEMPLATE_TEXT) {
1800:                            parseElementsTemplateText(parent);
1801:                        }
1802:                    }
1803:                    err.jspError(start, "jsp.error.unterminated", "&lt;" + tag);
1804:                } else {
1805:                    err.jspError(start, "jasper.error.bad.bodycontent.type");
1806:                }
1807:            }
1808:
1809:            /*
1810:             * Parses named attributes.
1811:             */
1812:            private void parseNamedAttributes(Node parent)
1813:                    throws JasperException {
1814:                do {
1815:                    Mark start = reader.mark();
1816:                    Attributes attrs = parseAttributes();
1817:                    Node.NamedAttribute namedAttributeNode = new Node.NamedAttribute(
1818:                            attrs, start, parent);
1819:
1820:                    reader.skipSpaces();
1821:                    if (!reader.matches("/>")) {
1822:                        if (!reader.matches(">")) {
1823:                            err.jspError(start, "jsp.error.unterminated",
1824:                                    "&lt;jsp:attribute");
1825:                        }
1826:                        if (namedAttributeNode.isTrim()) {
1827:                            reader.skipSpaces();
1828:                        }
1829:                        parseBody(namedAttributeNode, "jsp:attribute",
1830:                                getAttributeBodyType(parent, attrs
1831:                                        .getValue("name")));
1832:                        if (namedAttributeNode.isTrim()) {
1833:                            Node.Nodes subElems = namedAttributeNode.getBody();
1834:                            if (subElems != null) {
1835:                                Node lastNode = subElems.getNode(subElems
1836:                                        .size() - 1);
1837:                                if (lastNode instanceof  Node.TemplateText) {
1838:                                    ((Node.TemplateText) lastNode).rtrim();
1839:                                }
1840:                            }
1841:                        }
1842:                    }
1843:                    reader.skipSpaces();
1844:                } while (reader.matches("<jsp:attribute"));
1845:            }
1846:
1847:            /**
1848:             * Determine the body type of <jsp:attribute> from the enclosing node
1849:             */
1850:            private String getAttributeBodyType(Node n, String name) {
1851:
1852:                if (n instanceof  Node.CustomTag) {
1853:                    TagInfo tagInfo = ((Node.CustomTag) n).getTagInfo();
1854:                    TagAttributeInfo[] tldAttrs = tagInfo.getAttributes();
1855:                    for (int i = 0; i < tldAttrs.length; i++) {
1856:                        if (name.equals(tldAttrs[i].getName())) {
1857:                            if (tldAttrs[i].isFragment()) {
1858:                                return TagInfo.BODY_CONTENT_SCRIPTLESS;
1859:                            }
1860:                            if (tldAttrs[i].canBeRequestTime()) {
1861:                                return TagInfo.BODY_CONTENT_JSP;
1862:                            }
1863:                        }
1864:                    }
1865:                    if (tagInfo.hasDynamicAttributes()) {
1866:                        return TagInfo.BODY_CONTENT_JSP;
1867:                    }
1868:                } else if (n instanceof  Node.IncludeAction) {
1869:                    if ("page".equals(name)) {
1870:                        return TagInfo.BODY_CONTENT_JSP;
1871:                    }
1872:                } else if (n instanceof  Node.ForwardAction) {
1873:                    if ("page".equals(name)) {
1874:                        return TagInfo.BODY_CONTENT_JSP;
1875:                    }
1876:                } else if (n instanceof  Node.SetProperty) {
1877:                    if ("value".equals(name)) {
1878:                        return TagInfo.BODY_CONTENT_JSP;
1879:                    }
1880:                } else if (n instanceof  Node.UseBean) {
1881:                    if ("beanName".equals(name)) {
1882:                        return TagInfo.BODY_CONTENT_JSP;
1883:                    }
1884:                } else if (n instanceof  Node.PlugIn) {
1885:                    if ("width".equals(name) || "height".equals(name)) {
1886:                        return TagInfo.BODY_CONTENT_JSP;
1887:                    }
1888:                } else if (n instanceof  Node.ParamAction) {
1889:                    if ("value".equals(name)) {
1890:                        return TagInfo.BODY_CONTENT_JSP;
1891:                    }
1892:                } else if (n instanceof  Node.JspElement) {
1893:                    return TagInfo.BODY_CONTENT_JSP;
1894:                }
1895:
1896:                return JAVAX_BODY_CONTENT_TEMPLATE_TEXT;
1897:            }
1898:
1899:            private void parseTagFileDirectives(Node parent)
1900:                    throws JasperException {
1901:                reader.setSingleFile(true);
1902:                reader.skipUntil("<");
1903:                while (reader.hasMoreInput()) {
1904:                    start = reader.mark();
1905:                    if (reader.matches("%--")) {
1906:                        parseComment(parent);
1907:                    } else if (reader.matches("%@")) {
1908:                        parseDirective(parent);
1909:                    } else if (reader.matches("jsp:directive.")) {
1910:                        parseXMLDirective(parent);
1911:                    }
1912:                    reader.skipUntil("<");
1913:                }
1914:            }
1915:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.