Source Code Cross Referenced for Parser.java in  » Sevlet-Container » apache-tomcat-6.0.14 » 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 » apache tomcat 6.0.14 » org.apache.jasper.compiler 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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