0001: /*
0002: * The Apache Software License, Version 1.1
0003: *
0004: * Copyright (c) 1999 The Apache Software Foundation. All rights
0005: * reserved.
0006: *
0007: * Redistribution and use in source and binary forms, with or without
0008: * modification, are permitted provided that the following conditions
0009: * are met:
0010: *
0011: * 1. Redistributions of source code must retain the above copyright
0012: * notice, this list of conditions and the following disclaimer.
0013: *
0014: * 2. Redistributions in binary form must reproduce the above copyright
0015: * notice, this list of conditions and the following disclaimer in
0016: * the documentation and/or other materials provided with the
0017: * distribution.
0018: *
0019: * 3. The end-user documentation included with the redistribution, if
0020: * any, must include the following acknowlegement:
0021: * "This product includes software developed by the
0022: * Apache Software Foundation (http://www.apache.org/)."
0023: * Alternately, this acknowlegement may appear in the software itself,
0024: * if and wherever such third-party acknowlegements normally appear.
0025: *
0026: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
0027: * Foundation" must not be used to endorse or promote products derived
0028: * from this software without prior written permission. For written
0029: * permission, please contact apache@apache.org.
0030: *
0031: * 5. Products derived from this software may not be called "Apache"
0032: * nor may "Apache" appear in their names without prior written
0033: * permission of the Apache Group.
0034: *
0035: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0046: * SUCH DAMAGE.
0047: * ====================================================================
0048: *
0049: * This software consists of voluntary contributions made by many
0050: * individuals on behalf of the Apache Software Foundation. For more
0051: * information on the Apache Software Foundation, please see
0052: * <http://www.apache.org/>.
0053: *
0054: */
0055: package com.sun.portal.providers.jsp.jasper3.jasper.compiler;
0056:
0057: import java.util.Vector;
0058: import java.util.Hashtable;
0059: import java.util.Enumeration;
0060:
0061: import java.io.CharArrayWriter;
0062: import com.sun.portal.providers.jsp.jasper3.jasper.JasperException;
0063: import com.sun.portal.providers.jsp.jasper3.jasper.Constants;
0064:
0065: import javax.servlet.jsp.tagext.TagLibraryInfo;
0066: import javax.servlet.jsp.tagext.TagInfo;
0067:
0068: import com.sun.portal.providers.jsp.jasper3.tomcat.logging.Logger;
0069:
0070: /**
0071: * The class that parses the JSP input and calls the right methods on
0072: * the code generator backend.
0073: *
0074: * @author Anil K. Vijendran
0075: * @author Rajiv Mordani
0076: */
0077: public class Parser {
0078: /**
0079: * The input source we read from...
0080: */
0081: private JspReader reader;
0082:
0083: /**
0084: * The backend that is notified of constructs recognized in the input...
0085: */
0086: private ParseEventListener listener;
0087:
0088: /*
0089: * Char buffer for HTML data
0090: */
0091: CharArrayWriter caw;
0092:
0093: /*
0094: * Marker for start and end of the tempate data.
0095: */
0096: Mark tmplStart;
0097: Mark tmplStop;
0098:
0099: /*
0100: * Name of the current file.
0101: * Useful to preserve the line number information in
0102: * case of an include.
0103: */
0104: String currentFile;
0105:
0106: public interface Action {
0107: void execute(Mark start, Mark stop) throws JasperException;
0108: }
0109:
0110: public Parser(JspReader reader, final ParseEventListener lnr) {
0111: this .reader = reader;
0112: this .listener = new DelegatingListener(lnr, new Action() {
0113: public void execute(Mark start, Mark stop)
0114: throws JasperException {
0115: Parser.this .flushCharData(start, stop);
0116: }
0117: });
0118: this .caw = new CharArrayWriter();
0119: this .currentFile = reader.mark().getFile();
0120: }
0121:
0122: static final Vector coreElements = new Vector();
0123:
0124: /*
0125: * JSP directives
0126: */
0127: static final class Directive implements CoreElement {
0128: private static final String OPEN_DIRECTIVE = "<%@";
0129: private static final String CLOSE_DIRECTIVE = "%>";
0130:
0131: static final String[] directives = { "page", "include",
0132: "taglib" };
0133:
0134: private static final JspUtil.ValidAttribute[] pageDvalidAttrs = {
0135: new JspUtil.ValidAttribute("language"),
0136: new JspUtil.ValidAttribute("extends"),
0137: new JspUtil.ValidAttribute("import"),
0138: new JspUtil.ValidAttribute("session"),
0139: new JspUtil.ValidAttribute("buffer"),
0140: new JspUtil.ValidAttribute("autoFlush"),
0141: new JspUtil.ValidAttribute("isThreadSafe"),
0142: new JspUtil.ValidAttribute("info"),
0143: new JspUtil.ValidAttribute("errorPage"),
0144: new JspUtil.ValidAttribute("isErrorPage"),
0145: new JspUtil.ValidAttribute("contentType") };
0146:
0147: private static final JspUtil.ValidAttribute[] includeDvalidAttrs = { new JspUtil.ValidAttribute(
0148: "file", true) };
0149:
0150: private static final JspUtil.ValidAttribute[] tagDvalidAttrs = {
0151: new JspUtil.ValidAttribute("uri", true),
0152: new JspUtil.ValidAttribute("prefix", true) };
0153:
0154: public boolean accept(ParseEventListener listener,
0155: JspReader reader, Parser parser) throws JasperException {
0156: String close;
0157: String open;
0158:
0159: if (reader.matches(OPEN_DIRECTIVE)) {
0160: open = OPEN_DIRECTIVE;
0161: close = CLOSE_DIRECTIVE;
0162: } else
0163: return false;
0164:
0165: Mark start = reader.mark();
0166: reader.advance(open.length());
0167: reader.skipSpaces();
0168:
0169: // Check which directive it is.
0170: String match = null;
0171: for (int i = 0; i < directives.length; i++)
0172: if (reader.matches(directives[i])) {
0173: match = directives[i];
0174: break;
0175: }
0176: if (match == null)
0177: throw new ParseException(reader.mark(), Constants
0178: .getString("jsp.error.invalid.directive"));
0179:
0180: reader.advance(match.length());
0181:
0182: // Parse the attr-val pairs.
0183: Hashtable attrs = reader.parseTagAttributes();
0184: if (match.equals("page"))
0185: JspUtil.checkAttributes("Page directive", attrs,
0186: pageDvalidAttrs, start);
0187: else if (match.equals("include"))
0188: JspUtil.checkAttributes("Include directive", attrs,
0189: includeDvalidAttrs, start);
0190: else if (match.equals("taglib"))
0191: JspUtil.checkAttributes("Taglib directive", attrs,
0192: tagDvalidAttrs, start);
0193:
0194: // Match close.
0195: reader.skipSpaces();
0196: if (!reader.matches(close))
0197: throw new ParseException(reader.mark(), Constants
0198: .getString("jsp.error.unterminated",
0199: new Object[] { open }));
0200: else
0201: reader.advance(close.length());
0202:
0203: Mark stop = reader.mark();
0204:
0205: listener.setTemplateInfo(parser.tmplStart, parser.tmplStop);
0206: listener.handleDirective(match, start, stop, attrs);
0207: return true;
0208: }
0209:
0210: }
0211:
0212: static {
0213: coreElements.addElement(new Directive());
0214: }
0215:
0216: /*
0217: * Include action
0218: */
0219: static final class Include implements CoreElement {
0220: private static final String OPEN_INCLUDE = "<jsp:include";
0221: private static final String CLOSE_INCLUDE_NO_BODY = "/>";
0222: private static final String CLOSE_INCLUDE_BODY = ">";
0223: private static final String CLOSE_INCLUDE = "</jsp:include>";
0224: private static final String OPEN_INDIVIDUAL_PARAM = "<jsp:param";
0225: private static final String CLOSE_INDIVIDUAL_PARAM = "/>";
0226:
0227: private static final JspUtil.ValidAttribute[] validAttributes = {
0228: new JspUtil.ValidAttribute("page", true),
0229: new JspUtil.ValidAttribute("flush") };
0230:
0231: public boolean accept(ParseEventListener listener,
0232: JspReader reader, Parser parser) throws JasperException {
0233: if (reader.matches(OPEN_INCLUDE)) {
0234: Hashtable param = new Hashtable();
0235: Mark start = reader.mark();
0236: reader.advance(OPEN_INCLUDE.length());
0237: Hashtable attrs = reader.parseTagAttributes();
0238: JspUtil.checkAttributes("Include", attrs,
0239: validAttributes, start);
0240: reader.skipSpaces();
0241:
0242: if (!reader.matches(CLOSE_INCLUDE_NO_BODY)) {
0243:
0244: if (!reader.matches(CLOSE_INCLUDE_BODY))
0245: throw new ParseException(reader.mark(),
0246: Constants.getString(
0247: "jsp.error.unterminated",
0248: new Object[] { OPEN_INCLUDE }));
0249: reader.advance(CLOSE_INCLUDE_BODY.length());
0250:
0251: reader.skipSpaces();
0252: if (!reader.matches(CLOSE_INCLUDE)) {
0253:
0254: // Parse the params.
0255: reader.skipSpaces();
0256: if (!reader.matches(OPEN_INDIVIDUAL_PARAM))
0257: throw new ParseException(
0258: reader.mark(),
0259: Constants
0260: .getString("jsp.error.paramexpected"));
0261:
0262: //Parse zero or more param tags.
0263: while (reader.matches(OPEN_INDIVIDUAL_PARAM)) {
0264:
0265: reader.parsePluginParamTag(param);
0266: reader.skipSpaces();
0267:
0268: if (!reader.matches(CLOSE_INDIVIDUAL_PARAM))
0269: throw new ParseException(
0270: reader.mark(),
0271: Constants
0272: .getString(
0273: "jsp.error.unterminated",
0274: new Object[] { OPEN_INDIVIDUAL_PARAM }));
0275: reader.advance(CLOSE_INDIVIDUAL_PARAM
0276: .length());
0277: reader.skipSpaces();
0278: }
0279: }
0280:
0281: if (!reader.matches(CLOSE_INCLUDE))
0282: throw new ParseException(reader.mark(),
0283: Constants.getString(
0284: "jsp.error.unterminated",
0285: new Object[] { OPEN_INCLUDE }));
0286: reader.advance(CLOSE_INCLUDE.length());
0287: } else
0288: reader.advance(CLOSE_INCLUDE_NO_BODY.length());
0289: Mark stop = reader.mark();
0290: listener.setTemplateInfo(parser.tmplStart,
0291: parser.tmplStop);
0292: listener.handleInclude(start, stop, attrs, param);
0293: return true;
0294: } else
0295: return false;
0296: }
0297: }
0298:
0299: static {
0300: coreElements.addElement(new Include());
0301: }
0302:
0303: /*
0304: * Forward action
0305: */
0306: static final class Forward implements CoreElement {
0307: private static final String OPEN_FORWARD = "<jsp:forward";
0308: private static final String CLOSE_FORWARD_NO_BODY = "/>";
0309: private static final String CLOSE_FORWARD_BODY = ">";
0310: private static final String CLOSE_FORWARD = "</jsp:forward>";
0311: private static final String OPEN_INDIVIDUAL_PARAM = "<jsp:param";
0312: private static final String CLOSE_INDIVIDUAL_PARAM = "/>";
0313:
0314: private static final JspUtil.ValidAttribute[] validAttributes = { new JspUtil.ValidAttribute(
0315: "page", true) };
0316:
0317: public boolean accept(ParseEventListener listener,
0318: JspReader reader, Parser parser) throws JasperException {
0319: if (reader.matches(OPEN_FORWARD)) {
0320: Mark start = reader.mark();
0321: reader.advance(OPEN_FORWARD.length());
0322: Hashtable attrs = reader.parseTagAttributes();
0323: Hashtable param = new Hashtable();
0324: JspUtil.checkAttributes("Forward", attrs,
0325: validAttributes, start);
0326: reader.skipSpaces();
0327: if (!reader.matches(CLOSE_FORWARD_NO_BODY)) {
0328: if (!reader.matches(CLOSE_FORWARD_BODY))
0329: throw new ParseException(reader.mark(),
0330: Constants.getString(
0331: "jsp.error.unterminated",
0332: new Object[] { OPEN_FORWARD }));
0333: reader.advance(CLOSE_FORWARD_BODY.length());
0334: reader.skipSpaces();
0335:
0336: if (!reader.matches(CLOSE_FORWARD)) {
0337:
0338: // Parse the params.
0339: reader.skipSpaces();
0340: if (!reader.matches(OPEN_INDIVIDUAL_PARAM))
0341: throw new ParseException(
0342: reader.mark(),
0343: Constants
0344: .getString("jsp.error.paramexpected"));
0345: // Parse zero or more param tags.
0346: while (reader.matches(OPEN_INDIVIDUAL_PARAM)) {
0347:
0348: //Borrow plugin's parse function.
0349: reader.parsePluginParamTag(param);
0350: reader.skipSpaces();
0351:
0352: if (!reader.matches(CLOSE_INDIVIDUAL_PARAM))
0353: throw new ParseException(
0354: reader.mark(),
0355: Constants
0356: .getString(
0357: "jsp.error.unterminated",
0358: new Object[] { OPEN_INDIVIDUAL_PARAM }));
0359: reader.advance(CLOSE_INDIVIDUAL_PARAM
0360: .length());
0361: reader.skipSpaces();
0362: }
0363: }
0364:
0365: if (!reader.matches(CLOSE_FORWARD))
0366: throw new ParseException(reader.mark(),
0367: Constants.getString(
0368: "jsp.error.unterminated",
0369: new Object[] { OPEN_FORWARD }));
0370: reader.advance(CLOSE_FORWARD.length());
0371: } else
0372: reader.advance(CLOSE_FORWARD_NO_BODY.length());
0373:
0374: Mark stop = reader.mark();
0375: listener.setTemplateInfo(parser.tmplStart,
0376: parser.tmplStop);
0377: listener.handleForward(start, stop, attrs, param);
0378: return true;
0379: } else
0380: return false;
0381: }
0382: }
0383:
0384: static {
0385: coreElements.addElement(new Forward());
0386: }
0387:
0388: /*
0389: * Jsp comments <%-- stuff --%>
0390: */
0391:
0392: // declarations
0393: static final class Comment implements CoreElement {
0394:
0395: private static final String OPEN_COMMENT = "<%--";
0396: private static final String CLOSE_COMMENT = "--%>";
0397:
0398: public boolean accept(ParseEventListener listener,
0399: JspReader reader, Parser parser) throws JasperException {
0400:
0401: if (reader.matches(OPEN_COMMENT)) {
0402: reader.advance(OPEN_COMMENT.length());
0403: Mark start = reader.mark();
0404: Mark stop = reader.skipUntil(CLOSE_COMMENT);
0405: if (stop == null)
0406: throw new ParseException(Constants.getString(
0407: "jsp.error.unterminated",
0408: new Object[] { OPEN_COMMENT }));
0409:
0410: parser.flushCharData(parser.tmplStart, parser.tmplStop);
0411: return true;
0412: }
0413: return false;
0414: }
0415: }
0416:
0417: static {
0418: coreElements.addElement(new Comment());
0419: }
0420:
0421: /*
0422: * Scripting elements
0423: */
0424:
0425: // declarations
0426: static final class Declaration implements CoreElement {
0427:
0428: private static final String OPEN_DECL = "<%!";
0429: private static final String CLOSE_DECL = "%>";
0430:
0431: private static final JspUtil.ValidAttribute[] validAttributes = {};
0432:
0433: public boolean accept(ParseEventListener listener,
0434: JspReader reader, Parser parser) throws JasperException {
0435: String close, open, end_open = null;
0436: Hashtable attrs = null;
0437: Mark start;
0438:
0439: if (reader.matches(OPEN_DECL)) {
0440: open = OPEN_DECL;
0441: close = CLOSE_DECL;
0442: } else
0443: return false;
0444:
0445: reader.advance(open.length());
0446: start = reader.mark();
0447:
0448: if (end_open != null) {
0449: attrs = reader.parseTagAttributes();
0450:
0451: reader.skipSpaces();
0452: if (!reader.matches(end_open))
0453: throw new ParseException(reader.mark(), Constants
0454: .getString("jsp.error.unterminated"));
0455: reader.advance(end_open.length());
0456: reader.skipSpaces();
0457:
0458: JspUtil.checkAttributes("Declaration", attrs,
0459: validAttributes, start);
0460: }
0461:
0462: Mark stop = reader.skipUntil(close);
0463: if (stop == null)
0464: throw new ParseException(Constants
0465: .getString("jsp.error.unterminated",
0466: new Object[] { open }));
0467:
0468: listener.setTemplateInfo(parser.tmplStart, parser.tmplStop);
0469: listener.handleDeclaration(start, stop, attrs);
0470: return true;
0471: }
0472: }
0473:
0474: static {
0475: coreElements.addElement(new Declaration());
0476: }
0477:
0478: // expressions
0479: static final class Expression implements CoreElement {
0480:
0481: private static final String OPEN_EXPR = "<%=";
0482: private static final String CLOSE_EXPR = "%>";
0483:
0484: private static final JspUtil.ValidAttribute[] validAttributes = {};
0485:
0486: public boolean accept(ParseEventListener listener,
0487: JspReader reader, Parser parser) throws JasperException {
0488: String close, open, end_open = null;
0489: Hashtable attrs = null;
0490: Mark start;
0491:
0492: if (reader.matches(OPEN_EXPR)) {
0493: open = OPEN_EXPR;
0494: close = CLOSE_EXPR;
0495: } else
0496: return false;
0497:
0498: reader.advance(open.length());
0499: start = reader.mark();
0500:
0501: if (end_open != null) {
0502: attrs = reader.parseTagAttributes();
0503:
0504: reader.skipSpaces();
0505: if (!reader.matches(end_open))
0506: throw new ParseException(reader.mark(), Constants
0507: .getString("jsp.error.unterminated"));
0508: reader.advance(end_open.length());
0509: reader.skipSpaces();
0510:
0511: JspUtil.checkAttributes("Expression", attrs,
0512: validAttributes, start);
0513: }
0514:
0515: Mark stop = reader.skipUntil(close);
0516: if (stop == null)
0517: throw new ParseException(reader.mark(), Constants
0518: .getString("jsp.error.unterminated",
0519: new Object[] { open }));
0520: listener.setTemplateInfo(parser.tmplStart, parser.tmplStop);
0521: listener.handleExpression(start, stop, attrs);
0522: return true;
0523: }
0524: }
0525:
0526: static {
0527: coreElements.addElement(new Expression());
0528: }
0529:
0530: // scriptlets
0531: static final class Scriptlet implements CoreElement {
0532:
0533: private static final String OPEN_SCRIPTLET = "<%";
0534: private static final String CLOSE_SCRIPTLET = "%>";
0535:
0536: private static final JspUtil.ValidAttribute[] validAttributes = {};
0537:
0538: public boolean accept(ParseEventListener listener,
0539: JspReader reader, Parser parser) throws JasperException {
0540: String close, open, end_open = null;
0541: Hashtable attrs = null;
0542: Mark start;
0543:
0544: if (reader.matches(OPEN_SCRIPTLET)) {
0545: open = OPEN_SCRIPTLET;
0546: close = CLOSE_SCRIPTLET;
0547: } else
0548: return false;
0549:
0550: reader.advance(open.length());
0551: start = reader.mark();
0552:
0553: if (end_open != null) {
0554: attrs = reader.parseTagAttributes();
0555:
0556: reader.skipSpaces();
0557: if (!reader.matches(end_open))
0558: throw new ParseException(reader.mark(), Constants
0559: .getString("jsp.error.unterminated"));
0560: reader.advance(end_open.length());
0561: reader.skipSpaces();
0562:
0563: JspUtil.checkAttributes("Scriptlet", attrs,
0564: validAttributes, start);
0565: }
0566:
0567: Mark stop = reader.skipUntil(close);
0568: if (stop == null)
0569: throw new ParseException(reader.mark(), Constants
0570: .getString("jsp.error.unterminated",
0571: new Object[] { open }));
0572: listener.setTemplateInfo(parser.tmplStart, parser.tmplStop);
0573: listener.handleScriptlet(start, stop, attrs);
0574: return true;
0575: }
0576: }
0577:
0578: static {
0579: coreElements.addElement(new Scriptlet());
0580: }
0581:
0582: /*
0583: * UseBean
0584: */
0585: static final class Bean implements CoreElement {
0586:
0587: private static final String OPEN_BEAN = "<jsp:useBean";
0588: private static final String CLOSE_BEAN = "/>";
0589: private static final String CLOSE_BEAN_2 = "</jsp:useBean>";
0590: private static final String CLOSE_BEAN_3 = ">";
0591:
0592: private static final JspUtil.ValidAttribute[] validAttributes = {
0593: new JspUtil.ValidAttribute("id"),
0594: new JspUtil.ValidAttribute("scope"),
0595: new JspUtil.ValidAttribute("class"),
0596: new JspUtil.ValidAttribute("type"),
0597: new JspUtil.ValidAttribute("beanName") };
0598:
0599: public boolean accept(ParseEventListener listener,
0600: JspReader reader, Parser parser) throws JasperException {
0601: if (reader.matches(OPEN_BEAN)) {
0602: Mark start = reader.mark();
0603: reader.advance(OPEN_BEAN.length());
0604: Hashtable attrs = reader.parseTagAttributesBean();
0605: JspUtil.checkAttributes("useBean", attrs,
0606: validAttributes, start);
0607: reader.skipSpaces();
0608: if (!reader.matches(CLOSE_BEAN)) {
0609: if (!reader.matches(CLOSE_BEAN_3))
0610: throw new ParseException(reader.mark(),
0611: Constants.getString(
0612: "jsp.error.unterminated",
0613: new Object[] { "useBean" }));
0614: reader.advance(CLOSE_BEAN_3.length());
0615: Mark stop = reader.mark();
0616: listener.setTemplateInfo(parser.tmplStart,
0617: parser.tmplStop);
0618: /* As per section 2.13.1.1 in the Jsp 1.1 spec
0619: If the jsp:useBean doesn't have a body it is of the
0620: form:
0621: <jsp:useBean ...... />
0622: Else, if the jsp:useBean has a body then it is of the
0623: form:
0624: <jsp:useBean ...... >
0625: body
0626: </jsp:useBean>
0627:
0628: Hence, the isBodyEmpty parameter's value is false,
0629: since, this part of the code is within an if
0630: condition for the second form (non-empty body).
0631: */
0632: listener.handleBean(start, stop, attrs, false);
0633:
0634: int oldSize = reader.size;
0635: parser.parse(CLOSE_BEAN_2);
0636: if (oldSize != reader.size) {
0637: throw new ParseException(
0638: reader.mark(),
0639: Constants
0640: .getString("jsp.error.usebean.notinsamefile"));
0641: }
0642: if (!reader.matches(CLOSE_BEAN_2))
0643: throw new ParseException(reader.mark(),
0644: Constants.getString(
0645: "jsp.error.unterminated",
0646: new Object[] { OPEN_BEAN }));
0647:
0648: reader.advance(CLOSE_BEAN_2.length());
0649:
0650: // As per section 2.13.1.1 in the Jsp 1.1 spec
0651: listener.handleBeanEnd(start, stop, attrs, false);
0652:
0653: return true;
0654: } else {
0655: reader.advance(CLOSE_BEAN.length());
0656: Mark stop = reader.mark();
0657: listener.setTemplateInfo(parser.tmplStart,
0658: parser.tmplStop);
0659: // As per section 2.13.1.1 in the Jsp 1.1 spec
0660: listener.handleBean(start, stop, attrs, true);
0661: listener.handleBeanEnd(start, stop, attrs, true);
0662:
0663: return true;
0664: }
0665: } else
0666: return false;
0667: }
0668: }
0669:
0670: static {
0671: coreElements.addElement(new Bean());
0672: }
0673:
0674: /*
0675: * GetProperty
0676: */
0677: static final class GetProperty implements CoreElement {
0678:
0679: private static final String OPEN_GETPROPERTY = "<jsp:getProperty";
0680: private static final String CLOSE_GETPROPERTY = "/>";
0681:
0682: private static final JspUtil.ValidAttribute[] validAttributes = {
0683: new JspUtil.ValidAttribute("name", true),
0684: new JspUtil.ValidAttribute("property", true) };
0685:
0686: public boolean accept(ParseEventListener listener,
0687: JspReader reader, Parser parser) throws JasperException {
0688: if (reader.matches(OPEN_GETPROPERTY)) {
0689: Mark start = reader.mark();
0690: reader.advance(OPEN_GETPROPERTY.length());
0691: Hashtable attrs = reader.parseTagAttributes();
0692: JspUtil.checkAttributes("getProperty", attrs,
0693: validAttributes, start);
0694: reader.skipSpaces();
0695: if (!reader.matches(CLOSE_GETPROPERTY))
0696: throw new ParseException(reader.mark(), Constants
0697: .getString("jsp.error.unterminated",
0698: new Object[] { OPEN_GETPROPERTY }));
0699: else
0700: reader.advance(CLOSE_GETPROPERTY.length());
0701: Mark stop = reader.mark();
0702: listener.setTemplateInfo(parser.tmplStart,
0703: parser.tmplStop);
0704: listener.handleGetProperty(start, stop, attrs);
0705: return true;
0706: } else
0707: return false;
0708: }
0709: }
0710:
0711: static {
0712: coreElements.addElement(new GetProperty());
0713: }
0714:
0715: /*
0716: * SetProperty
0717: */
0718: static final class SetProperty implements CoreElement {
0719:
0720: private static final String OPEN_SETPROPERTY = "<jsp:setProperty";
0721: private static final String CLOSE_SETPROPERTY = "/>";
0722:
0723: private static final JspUtil.ValidAttribute[] validAttributes = {
0724: new JspUtil.ValidAttribute("name", true),
0725: new JspUtil.ValidAttribute("property", true),
0726: new JspUtil.ValidAttribute("value"),
0727: new JspUtil.ValidAttribute("param") };
0728:
0729: public boolean accept(ParseEventListener listener,
0730: JspReader reader, Parser parser) throws JasperException {
0731: if (reader.matches(OPEN_SETPROPERTY)) {
0732: Mark start = reader.mark();
0733: reader.advance(OPEN_SETPROPERTY.length());
0734: Hashtable attrs = reader.parseTagAttributes();
0735: JspUtil.checkAttributes("setProperty", attrs,
0736: validAttributes, start);
0737: reader.skipSpaces();
0738: if (!reader.matches(CLOSE_SETPROPERTY))
0739: throw new ParseException(reader.mark(), Constants
0740: .getString("jsp.error.unterminated",
0741: new Object[] { OPEN_SETPROPERTY }));
0742: else
0743: reader.advance(CLOSE_SETPROPERTY.length());
0744: Mark stop = reader.mark();
0745: listener.setTemplateInfo(parser.tmplStart,
0746: parser.tmplStop);
0747: listener.handleSetProperty(start, stop, attrs);
0748: return true;
0749: } else
0750: return false;
0751: }
0752: }
0753:
0754: static {
0755: coreElements.addElement(new SetProperty());
0756: }
0757:
0758: /*
0759: * User-defined Tags
0760: */
0761: static final class Tag implements CoreElement {
0762:
0763: private static final String CLOSE_1 = "/>";
0764: private static final String CLOSE = ">";
0765:
0766: public boolean accept(ParseEventListener listener,
0767: JspReader reader, Parser parser) throws JasperException {
0768: if (reader.peekChar() != '<')
0769: return false;
0770:
0771: Mark start = reader.mark();
0772: reader.nextChar();
0773: String tag = reader.parseToken(false);
0774:
0775: /*
0776: * Extract the prefix and the short tag name.
0777: */
0778: int i = tag.indexOf(':');
0779: if (i == -1) {
0780: reader.reset(start);
0781: return false;
0782: }
0783: String prefix = tag.substring(0, i);
0784: String shortTagName = "";
0785: if (++i < tag.length())
0786: shortTagName = tag.substring(i);
0787:
0788: /*
0789: * Check if this is a user-defined tag; otherwise we won't touch this...
0790: */
0791:
0792: TagLibraries libraries = listener.getTagLibraries();
0793:
0794: if (!libraries.isUserDefinedTag(prefix, shortTagName)) {
0795: reader.reset(start);
0796: return false;
0797: }
0798:
0799: if (shortTagName == null)
0800: throw new ParseException(start, "Nothing after the :");
0801:
0802: TagLibraryInfo tli = libraries.getTagLibInfo(prefix);
0803: TagInfo ti = tli.getTag(shortTagName);
0804:
0805: if (ti == null)
0806: throw new ParseException(start,
0807: "Unable to locate TagInfo for " + tag);
0808:
0809: String bc = ti.getBodyContent();
0810:
0811: Hashtable attrs = reader.parseTagAttributes();
0812: reader.skipSpaces();
0813: Mark bodyStart = null;
0814: Mark bodyStop = null;
0815:
0816: if (reader.matches(CLOSE_1)
0817: || bc.equalsIgnoreCase(TagInfo.BODY_CONTENT_EMPTY)) {
0818: if (reader.matches(CLOSE_1))
0819: reader.advance(CLOSE_1.length());
0820: else
0821: throw new ParseException(start,
0822: "Body is supposed to be empty for " + tag);
0823:
0824: listener.setTemplateInfo(parser.tmplStart,
0825: parser.tmplStop);
0826: listener.handleTagBegin(start, reader.mark(), attrs,
0827: prefix, shortTagName, tli, ti);
0828: listener.handleTagEnd(start, reader.mark(), prefix,
0829: shortTagName, attrs, tli, ti);
0830: } else {
0831: // Body can be either
0832: // - JSP tags
0833: // - tag dependent stuff
0834: if (reader.matches(CLOSE)) {
0835: reader.advance(CLOSE.length());
0836: bodyStart = reader.mark();
0837: listener.setTemplateInfo(parser.tmplStart,
0838: parser.tmplStop);
0839: listener.handleTagBegin(start, bodyStart, attrs,
0840: prefix, shortTagName, tli, ti);
0841: if (bc
0842: .equalsIgnoreCase(TagInfo.BODY_CONTENT_TAG_DEPENDENT)
0843: || bc
0844: .equalsIgnoreCase(TagInfo.BODY_CONTENT_JSP)) {
0845: String tagEnd = "</" + tag + ">";
0846: // Parse until the end of the tag body.
0847: // Then skip the tag end...
0848: parser.parse(tagEnd);
0849: try {
0850: reader.advance(tagEnd.length());
0851: } catch (ParseException ex) {
0852: throw new ParseException(
0853: start,
0854: Constants
0855: .getString(
0856: "jsp.error.unterminated.user.tag",
0857: new Object[] { JspUtil
0858: .escapeXml(tagEnd) }));
0859: }
0860: listener.setTemplateInfo(parser.tmplStart,
0861: parser.tmplStop);
0862: listener.handleTagEnd(parser.tmplStop, reader
0863: .mark(), prefix, shortTagName, attrs,
0864: tli, ti);
0865: } else
0866: throw new ParseException(start,
0867: "Internal Error: Invalid BODY_CONTENT type");
0868: } else
0869: throw new ParseException(start,
0870: "Unterminated user-defined tag");
0871: }
0872: return true;
0873: }
0874: }
0875:
0876: static {
0877: coreElements.addElement(new Tag());
0878: }
0879:
0880: /*
0881: * Plugin
0882: */
0883: static final class Plugin implements CoreElement {
0884: private static final String OPEN_PLUGIN = "<jsp:plugin";
0885: private static final String END_OPEN_PLUGIN = ">";
0886: private static final String CLOSE_PLUGIN = "</jsp:plugin>";
0887: private static final String OPEN_PARAMS = "<jsp:params>";
0888: private static final String CLOSE_PARAMS = "</jsp:params>";
0889: private static final String OPEN_INDIVIDUAL_PARAM = "<jsp:param";
0890: private static final String CLOSE_INDIVIDUAL_PARAM = "/>";
0891: private static final String OPEN_FALLBACK = "<jsp:fallback>";
0892: private static final String CLOSE_FALLBACK = "</jsp:fallback>";
0893:
0894: private static final JspUtil.ValidAttribute[] validAttributes = {
0895: new JspUtil.ValidAttribute("type", true),
0896: new JspUtil.ValidAttribute("code", true),
0897: new JspUtil.ValidAttribute("codebase"),
0898: new JspUtil.ValidAttribute("align"),
0899: new JspUtil.ValidAttribute("archive"),
0900: new JspUtil.ValidAttribute("height"),
0901: new JspUtil.ValidAttribute("hspace"),
0902: new JspUtil.ValidAttribute("jreversion"),
0903: new JspUtil.ValidAttribute("name"),
0904: new JspUtil.ValidAttribute("vspace"),
0905: new JspUtil.ValidAttribute("width"),
0906: new JspUtil.ValidAttribute("nspluginurl"),
0907: new JspUtil.ValidAttribute("iepluginurl") };
0908:
0909: public boolean accept(ParseEventListener listener,
0910: JspReader reader, Parser parser) throws JasperException {
0911: if (reader.matches(OPEN_PLUGIN)) {
0912: Mark start = reader.mark();
0913: reader.advance(OPEN_PLUGIN.length());
0914: Hashtable attrs = reader.parseTagAttributes();
0915: reader.skipSpaces();
0916:
0917: if (!reader.matches(END_OPEN_PLUGIN))
0918: throw new ParseException(reader.mark(), Constants
0919: .getString("jsp.error.plugin.notclosed"));
0920:
0921: reader.advance(END_OPEN_PLUGIN.length());
0922: reader.skipSpaces();
0923:
0924: Hashtable param = null;
0925: String fallback = null;
0926:
0927: JspUtil.checkAttributes("plugin", attrs,
0928: validAttributes, start);
0929: if (reader.matches(OPEN_PARAMS)) {
0930: param = new Hashtable();
0931: boolean paramsClosed = false;
0932: reader.advance(OPEN_PARAMS.length());
0933:
0934: /**
0935: * Can have more than one param tag. Hence get all the
0936: * params.
0937: */
0938:
0939: while (reader.hasMoreInput()) {
0940: reader.skipSpaces();
0941: if (reader.matches(CLOSE_PARAMS)) {
0942: paramsClosed = true;
0943: reader.advance(CLOSE_PARAMS.length());
0944: break;
0945: }
0946: if (!reader.matches(OPEN_INDIVIDUAL_PARAM))
0947: throw new ParseException(
0948: reader.mark(),
0949: Constants
0950: .getString("jsp.error.paramexpected"));
0951:
0952: reader.parsePluginParamTag(param);
0953: reader.skipSpaces();
0954:
0955: if (!reader.matches(CLOSE_INDIVIDUAL_PARAM))
0956: throw new ParseException(
0957: reader.mark(),
0958: Constants
0959: .getString("jsp.error.closeindividualparam"));
0960: reader.advance(CLOSE_INDIVIDUAL_PARAM.length());
0961: }
0962: if (!paramsClosed)
0963: throw new ParseException(
0964: reader.mark(),
0965: Constants
0966: .getString("jsp.error.closeparams"));
0967: reader.skipSpaces();
0968: }
0969:
0970: if (reader.matches(OPEN_FALLBACK)) {
0971: reader.advance(OPEN_FALLBACK.length());
0972: reader.skipSpaces();
0973: Mark fallBackStart = reader.mark();
0974: Mark fallBackStop = reader
0975: .skipUntil(CLOSE_FALLBACK);
0976: fallback = new String(reader.getChars(
0977: fallBackStart, fallBackStop));
0978: reader.skipSpaces();
0979: }
0980:
0981: if (!reader.matches(CLOSE_PLUGIN))
0982: throw new ParseException(reader.mark(), Constants
0983: .getString("jsp.error.unterminated",
0984: new Object[] { OPEN_PLUGIN }));
0985:
0986: reader.advance(CLOSE_PLUGIN.length());
0987: Mark stop = reader.mark();
0988: listener.setTemplateInfo(parser.tmplStart,
0989: parser.tmplStop);
0990: listener.handlePlugin(start, stop, attrs, param,
0991: fallback);
0992: return true;
0993: } else
0994: return false;
0995: }
0996: }
0997:
0998: static {
0999: coreElements.addElement(new Plugin());
1000: }
1001:
1002: /*
1003: * Quoting in template text.
1004: * Entities ' and "e;
1005: */
1006: static final class QuoteEscape implements CoreElement {
1007: /**
1008: * constants for escapes
1009: */
1010: private static String QUOTED_START_TAG = "<\\%";
1011: private static String QUOTED_END_TAG = "%\\>";
1012: private static String START_TAG = "<%";
1013: private static String END_TAG = "%>";
1014:
1015: private static final String APOS = "'";
1016: private static final String QUOTE = ""e;";
1017:
1018: public boolean accept(ParseEventListener listener,
1019: JspReader reader, Parser parser) throws JasperException {
1020: try {
1021: Mark start = reader.mark();
1022: if (reader.matches(QUOTED_START_TAG)) {
1023: reader.advance(QUOTED_START_TAG.length());
1024: Mark end = reader.mark();
1025: parser.caw.write(START_TAG);
1026: parser.flushCharData(start, end);
1027: return true;
1028: } else if (reader.matches(APOS)) {
1029: reader.advance(APOS.length());
1030: Mark end = reader.mark();
1031: parser.caw.write("\'");
1032: parser.flushCharData(start, end);
1033: return true;
1034: } else if (reader.matches(QUOTE)) {
1035: reader.advance(QUOTE.length());
1036: Mark end = reader.mark();
1037: parser.caw.write("\"");
1038: parser.flushCharData(start, end);
1039: return true;
1040: }
1041: } catch (java.io.IOException ex) {
1042: throw new JasperException(ex);
1043: }
1044: return false;
1045: }
1046: }
1047:
1048: static {
1049: coreElements.addElement(new QuoteEscape());
1050: }
1051:
1052: void flushCharData(Mark start, Mark stop) throws JasperException {
1053: char[] array = caw.toCharArray();
1054: if (array.length != 0) // Avoid unnecessary out.write("") statements...
1055: listener.handleCharData(start, stop, caw.toCharArray());
1056: caw = new CharArrayWriter();
1057: }
1058:
1059: public void parse() throws JasperException {
1060: parse(null);
1061: }
1062:
1063: public void parse(String until) throws JasperException {
1064: parse(until, null);
1065: }
1066:
1067: public void parse(String until, Class[] accept)
1068: throws JasperException {
1069:
1070: boolean noJspElement = false;
1071: while (reader.hasMoreInput()) {
1072: if (until != null && reader.matches(until))
1073: return;
1074:
1075: // If the file has changed because of a 'push' or a 'pop'
1076: // we must flush the character data for the old file.
1077: if (!reader.mark().getFile().equals(currentFile)) {
1078: flushCharData(tmplStart, tmplStop);
1079: currentFile = reader.mark().getFile();
1080: tmplStart = reader.mark();
1081: }
1082:
1083: Enumeration e = coreElements.elements();
1084:
1085: if (accept != null) {
1086: Vector v = new Vector();
1087: while (e.hasMoreElements()) {
1088: CoreElement c = (CoreElement) e.nextElement();
1089: for (int i = 0; i < accept.length; i++)
1090: if (c.getClass().equals(accept[i]))
1091: v.addElement(c);
1092: }
1093: e = v.elements();
1094: }
1095:
1096: boolean accepted = false;
1097: while (e.hasMoreElements()) {
1098: CoreElement c = (CoreElement) e.nextElement();
1099: Mark m = reader.mark();
1100: if (c.accept(listener, reader, this )) {
1101: Constants.message("jsp.message.accepted",
1102: new Object[] { c.getClass().getName(), m },
1103: Logger.DEBUG);
1104: accepted = true;
1105: noJspElement = false;
1106: break;
1107: }
1108: }
1109: if (!accepted) {
1110:
1111: // This is a hack. "reader.nextContent()" will just return
1112: // after it sees "<" -- not necessarily a JSP element. Using
1113: // a boolean we will ensure that tmplStart changes only when
1114: // strictly necessary.
1115: if (noJspElement == false) {
1116: tmplStart = reader.mark();
1117: noJspElement = true;
1118: }
1119: String s = reader.nextContent();
1120: tmplStop = reader.mark();
1121: caw.write(s, 0, s.length());
1122: }
1123: }
1124: flushCharData(tmplStart, tmplStop);
1125: }
1126: }
|