KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > jasper > compiler > JspDocumentParser


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17 package org.apache.jasper.compiler;
18
19 import java.io.CharArrayWriter JavaDoc;
20 import java.io.FileNotFoundException JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.io.InputStream JavaDoc;
23
24 import java.util.Iterator JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.jar.JarFile JavaDoc;
27
28 import javax.servlet.jsp.tagext.TagFileInfo JavaDoc;
29 import javax.servlet.jsp.tagext.TagInfo JavaDoc;
30 import javax.servlet.jsp.tagext.TagLibraryInfo JavaDoc;
31 import javax.xml.parsers.SAXParser JavaDoc;
32 import javax.xml.parsers.SAXParserFactory JavaDoc;
33
34 import org.apache.jasper.JasperException;
35 import org.apache.jasper.JspCompilationContext;
36 import org.xml.sax.Attributes JavaDoc;
37 import org.xml.sax.InputSource JavaDoc;
38 import org.xml.sax.Locator JavaDoc;
39 import org.xml.sax.SAXException JavaDoc;
40 import org.xml.sax.SAXParseException JavaDoc;
41 import org.xml.sax.XMLReader JavaDoc;
42 import org.xml.sax.ext.LexicalHandler JavaDoc;
43 import org.xml.sax.helpers.AttributesImpl JavaDoc;
44 import org.xml.sax.helpers.DefaultHandler JavaDoc;
45
46 /**
47  * Class implementing a parser for a JSP document, that is, a JSP page in XML
48  * syntax.
49  *
50  * @author Jan Luehe
51  * @author Kin-man Chung
52  */

53
54 class JspDocumentParser
55     extends DefaultHandler JavaDoc
56     implements LexicalHandler JavaDoc, TagConstants {
57
58     private static final String JavaDoc JSP_VERSION = "version";
59     private static final String JavaDoc LEXICAL_HANDLER_PROPERTY =
60         "http://xml.org/sax/properties/lexical-handler";
61     private static final String JavaDoc JSP_URI = "http://java.sun.com/JSP/Page";
62
63     private static final EnableDTDValidationException ENABLE_DTD_VALIDATION_EXCEPTION =
64         new EnableDTDValidationException(
65             "jsp.error.enable_dtd_validation",
66             null);
67
68     private ParserController parserController;
69     private JspCompilationContext ctxt;
70     private PageInfo pageInfo;
71     private String JavaDoc path;
72     private StringBuffer JavaDoc charBuffer;
73
74     // Node representing the XML element currently being parsed
75
private Node current;
76
77     /*
78      * Outermost (in the nesting hierarchy) node whose body is declared to be
79      * scriptless. If a node's body is declared to be scriptless, all its
80      * nested nodes must be scriptless, too.
81      */

82     private Node scriptlessBodyNode;
83
84     private Locator JavaDoc locator;
85
86     //Mark representing the start of the current element. Note
87
//that locator.getLineNumber() and locator.getColumnNumber()
88
//return the line and column numbers for the character
89
//immediately _following_ the current element. The underlying
90
//XMl parser eats white space that is not part of character
91
//data, so for Nodes that are not created from character data,
92
//this is the best we can do. But when we parse character data,
93
//we get an accurate starting location by starting with startMark
94
//as set by the previous element, and updating it as we advance
95
//through the characters.
96
private Mark startMark;
97
98     // Flag indicating whether we are inside DTD declarations
99
private boolean inDTD;
100
101     private boolean isValidating;
102
103     private ErrorDispatcher err;
104     private boolean isTagFile;
105     private boolean directivesOnly;
106     private boolean isTop;
107
108     // Nesting level of Tag dependent bodies
109
private int tagDependentNesting = 0;
110     // Flag set to delay incrmenting tagDependentNesting until jsp:body
111
// is first encountered
112
private boolean tagDependentPending = false;
113
114     /*
115      * Constructor
116      */

117     public JspDocumentParser(
118         ParserController pc,
119         String JavaDoc path,
120         boolean isTagFile,
121         boolean directivesOnly) {
122         this.parserController = pc;
123         this.ctxt = pc.getJspCompilationContext();
124         this.pageInfo = pc.getCompiler().getPageInfo();
125         this.err = pc.getCompiler().getErrorDispatcher();
126         this.path = path;
127         this.isTagFile = isTagFile;
128         this.directivesOnly = directivesOnly;
129         this.isTop = true;
130     }
131
132     /*
133      * Parses a JSP document by responding to SAX events.
134      *
135      * @throws JasperException
136      */

137     public static Node.Nodes parse(
138         ParserController pc,
139         String JavaDoc path,
140         JarFile JavaDoc jarFile,
141         Node parent,
142         boolean isTagFile,
143         boolean directivesOnly,
144         String JavaDoc pageEnc,
145         String JavaDoc jspConfigPageEnc,
146         boolean isEncodingSpecifiedInProlog,
147         boolean isBomPresent)
148         throws JasperException {
149
150         JspDocumentParser jspDocParser =
151             new JspDocumentParser(pc, path, isTagFile, directivesOnly);
152         Node.Nodes pageNodes = null;
153
154         try {
155
156             // Create dummy root and initialize it with given page encodings
157
Node.Root dummyRoot = new Node.Root(null, parent, true);
158             dummyRoot.setPageEncoding(pageEnc);
159             dummyRoot.setJspConfigPageEncoding(jspConfigPageEnc);
160             dummyRoot.setIsEncodingSpecifiedInProlog(
161                 isEncodingSpecifiedInProlog);
162             dummyRoot.setIsBomPresent(isBomPresent);
163             jspDocParser.current = dummyRoot;
164             if (parent == null) {
165                 jspDocParser.addInclude(
166                     dummyRoot,
167                     jspDocParser.pageInfo.getIncludePrelude());
168             } else {
169                 jspDocParser.isTop = false;
170             }
171
172             // Parse the input
173
SAXParser JavaDoc saxParser = getSAXParser(false, jspDocParser);
174             InputStream JavaDoc inStream = null;
175             try {
176                 inStream = JspUtil.getInputStream(path, jarFile,
177                                                   jspDocParser.ctxt,
178                                                   jspDocParser.err);
179                 saxParser.parse(new InputSource JavaDoc(inStream), jspDocParser);
180             } catch (EnableDTDValidationException e) {
181                 saxParser = getSAXParser(true, jspDocParser);
182                 jspDocParser.isValidating = true;
183                 if (inStream != null) {
184                     try {
185                         inStream.close();
186                     } catch (Exception JavaDoc any) {
187                     }
188                 }
189                 inStream = JspUtil.getInputStream(path, jarFile,
190                                                   jspDocParser.ctxt,
191                                                   jspDocParser.err);
192                 saxParser.parse(new InputSource JavaDoc(inStream), jspDocParser);
193             } finally {
194                 if (inStream != null) {
195                     try {
196                         inStream.close();
197                     } catch (Exception JavaDoc any) {
198                     }
199                 }
200             }
201
202             if (parent == null) {
203                 jspDocParser.addInclude(
204                     dummyRoot,
205                     jspDocParser.pageInfo.getIncludeCoda());
206             }
207
208             // Create Node.Nodes from dummy root
209
pageNodes = new Node.Nodes(dummyRoot);
210
211         } catch (IOException JavaDoc ioe) {
212             jspDocParser.err.jspError("jsp.error.data.file.read", path, ioe);
213         } catch (SAXParseException JavaDoc e) {
214             jspDocParser.err.jspError
215                 (new Mark(jspDocParser.ctxt, path, e.getLineNumber(),
216                           e.getColumnNumber()),
217                  e.getMessage());
218         } catch (Exception JavaDoc e) {
219             jspDocParser.err.jspError(e);
220         }
221
222         return pageNodes;
223     }
224
225     /*
226      * Processes the given list of included files.
227      *
228      * This is used to implement the include-prelude and include-coda
229      * subelements of the jsp-config element in web.xml
230      */

231     private void addInclude(Node parent, List JavaDoc files) throws SAXException JavaDoc {
232         if (files != null) {
233             Iterator JavaDoc iter = files.iterator();
234             while (iter.hasNext()) {
235                 String JavaDoc file = (String JavaDoc)iter.next();
236                 AttributesImpl JavaDoc attrs = new AttributesImpl JavaDoc();
237                 attrs.addAttribute("", "file", "file", "CDATA", file);
238
239                 // Create a dummy Include directive node
240
Node includeDir =
241                         new Node.IncludeDirective(attrs, null, // XXX
242
parent);
243                 processIncludeDirective(file, includeDir);
244             }
245         }
246     }
247
248     /*
249      * Receives notification of the start of an element.
250      *
251      * This method assigns the given tag attributes to one of 3 buckets:
252      *
253      * - "xmlns" attributes that represent (standard or custom) tag libraries.
254      * - "xmlns" attributes that do not represent tag libraries.
255      * - all remaining attributes.
256      *
257      * For each "xmlns" attribute that represents a custom tag library, the
258      * corresponding TagLibraryInfo object is added to the set of custom
259      * tag libraries.
260      */

261     public void startElement(
262         String JavaDoc uri,
263         String JavaDoc localName,
264         String JavaDoc qName,
265         Attributes JavaDoc attrs)
266         throws SAXException JavaDoc {
267
268         AttributesImpl JavaDoc taglibAttrs = null;
269         AttributesImpl JavaDoc nonTaglibAttrs = null;
270         AttributesImpl JavaDoc nonTaglibXmlnsAttrs = null;
271
272         processChars();
273
274         checkPrefixes(uri, qName, attrs);
275
276         if (directivesOnly &&
277             !(JSP_URI.equals(uri) && localName.startsWith(DIRECTIVE_ACTION))) {
278             return;
279         }
280
281         // jsp:text must not have any subelements
282
if (JSP_URI.equals(uri) && TEXT_ACTION.equals(current.getLocalName())) {
283             throw new SAXParseException JavaDoc(
284                 Localizer.getMessage("jsp.error.text.has_subelement"),
285                 locator);
286         }
287
288         startMark = new Mark(ctxt, path, locator.getLineNumber(),
289                              locator.getColumnNumber());
290
291         if (attrs != null) {
292             /*
293              * Notice that due to a bug in the underlying SAX parser, the
294              * attributes must be enumerated in descending order.
295              */

296             boolean isTaglib = false;
297             for (int i = attrs.getLength() - 1; i >= 0; i--) {
298                 isTaglib = false;
299                 String JavaDoc attrQName = attrs.getQName(i);
300                 if (!attrQName.startsWith("xmlns")) {
301                     if (nonTaglibAttrs == null) {
302                         nonTaglibAttrs = new AttributesImpl JavaDoc();
303                     }
304                     nonTaglibAttrs.addAttribute(
305                         attrs.getURI(i),
306                         attrs.getLocalName(i),
307                         attrs.getQName(i),
308                         attrs.getType(i),
309                         attrs.getValue(i));
310                 } else {
311                     if (attrQName.startsWith("xmlns:jsp")) {
312                         isTaglib = true;
313                     } else {
314                         String JavaDoc attrUri = attrs.getValue(i);
315                         // TaglibInfo for this uri already established in
316
// startPrefixMapping
317
isTaglib = pageInfo.hasTaglib(attrUri);
318                     }
319                     if (isTaglib) {
320                         if (taglibAttrs == null) {
321                             taglibAttrs = new AttributesImpl JavaDoc();
322                         }
323                         taglibAttrs.addAttribute(
324                             attrs.getURI(i),
325                             attrs.getLocalName(i),
326                             attrs.getQName(i),
327                             attrs.getType(i),
328                             attrs.getValue(i));
329                     } else {
330                         if (nonTaglibXmlnsAttrs == null) {
331                             nonTaglibXmlnsAttrs = new AttributesImpl JavaDoc();
332                         }
333                         nonTaglibXmlnsAttrs.addAttribute(
334                             attrs.getURI(i),
335                             attrs.getLocalName(i),
336                             attrs.getQName(i),
337                             attrs.getType(i),
338                             attrs.getValue(i));
339                     }
340                 }
341             }
342         }
343
344         Node node = null;
345
346         if (tagDependentPending && JSP_URI.equals(uri) &&
347                      localName.equals(BODY_ACTION)) {
348             tagDependentPending = false;
349             tagDependentNesting++;
350             current =
351                 parseStandardAction(
352                     qName,
353                     localName,
354                     nonTaglibAttrs,
355                     nonTaglibXmlnsAttrs,
356                     taglibAttrs,
357                     startMark,
358                     current);
359             return;
360         }
361
362         if (tagDependentPending && JSP_URI.equals(uri) &&
363                      localName.equals(ATTRIBUTE_ACTION)) {
364             current =
365                 parseStandardAction(
366                     qName,
367                     localName,
368                     nonTaglibAttrs,
369                     nonTaglibXmlnsAttrs,
370                     taglibAttrs,
371                     startMark,
372                     current);
373             return;
374         }
375
376         if (tagDependentPending) {
377             tagDependentPending = false;
378             tagDependentNesting++;
379         }
380
381         if (tagDependentNesting > 0) {
382             node =
383                 new Node.UninterpretedTag(
384                     qName,
385                     localName,
386                     nonTaglibAttrs,
387                     nonTaglibXmlnsAttrs,
388                     taglibAttrs,
389                     startMark,
390                     current);
391         } else if (JSP_URI.equals(uri)) {
392             node =
393                 parseStandardAction(
394                     qName,
395                     localName,
396                     nonTaglibAttrs,
397                     nonTaglibXmlnsAttrs,
398                     taglibAttrs,
399                     startMark,
400                     current);
401         } else {
402             node =
403                 parseCustomAction(
404                     qName,
405                     localName,
406                     uri,
407                     nonTaglibAttrs,
408                     nonTaglibXmlnsAttrs,
409                     taglibAttrs,
410                     startMark,
411                     current);
412             if (node == null) {
413                 node =
414                     new Node.UninterpretedTag(
415                         qName,
416                         localName,
417                         nonTaglibAttrs,
418                         nonTaglibXmlnsAttrs,
419                         taglibAttrs,
420                         startMark,
421                         current);
422             } else {
423                 // custom action
424
String JavaDoc bodyType = getBodyType((Node.CustomTag) node);
425
426                 if (scriptlessBodyNode == null
427                         && bodyType.equalsIgnoreCase(TagInfo.BODY_CONTENT_SCRIPTLESS)) {
428                     scriptlessBodyNode = node;
429                 }
430                 else if (TagInfo.BODY_CONTENT_TAG_DEPENDENT.equalsIgnoreCase(bodyType)) {
431                     tagDependentPending = true;
432                 }
433             }
434         }
435
436         current = node;
437     }
438
439     /*
440      * Receives notification of character data inside an element.
441      *
442      * The SAX does not call this method with all of the template text, but may
443      * invoke this method with chunks of it. This is a problem when we try
444      * to determine if the text contains only whitespaces, or when we are
445      * looking for an EL expression string. Therefore it is necessary to
446      * buffer and concatenate the chunks and process the concatenated text
447      * later (at beginTag and endTag)
448      *
449      * @param buf The characters
450      * @param offset The start position in the character array
451      * @param len The number of characters to use from the character array
452      *
453      * @throws SAXException
454      */

455     public void characters(char[] buf, int offset, int len) {
456
457         if (charBuffer == null) {
458             charBuffer = new StringBuffer JavaDoc();
459         }
460         charBuffer.append(buf, offset, len);
461     }
462
463     private void processChars() throws SAXException JavaDoc {
464
465         if (charBuffer == null || directivesOnly) {
466             return;
467         }
468
469         /*
470          * JSP.6.1.1: All textual nodes that have only white space are to be
471          * dropped from the document, except for nodes in a jsp:text element,
472          * and any leading and trailing white-space-only textual nodes in a
473          * jsp:attribute whose 'trim' attribute is set to FALSE, which are to
474          * be kept verbatim.
475          * JSP.6.2.3 defines white space characters.
476          */

477         boolean isAllSpace = true;
478         if (!(current instanceof Node.JspText)
479             && !(current instanceof Node.NamedAttribute)) {
480             for (int i = 0; i < charBuffer.length(); i++) {
481                 if (!(charBuffer.charAt(i) == ' '
482                     || charBuffer.charAt(i) == '\n'
483                     || charBuffer.charAt(i) == '\r'
484                     || charBuffer.charAt(i) == '\t')) {
485                     isAllSpace = false;
486                     break;
487                 }
488             }
489         }
490
491         if (!isAllSpace && tagDependentPending) {
492             tagDependentPending = false;
493             tagDependentNesting++;
494         }
495
496         if (tagDependentNesting > 0) {
497             if (charBuffer.length() > 0) {
498                 new Node.TemplateText(charBuffer.toString(), startMark, current);
499             }
500             startMark = new Mark(ctxt, path, locator.getLineNumber(),
501                                  locator.getColumnNumber());
502             charBuffer = null;
503             return;
504         }
505
506         if ((current instanceof Node.JspText)
507             || (current instanceof Node.NamedAttribute)
508             || !isAllSpace) {
509
510             int line = startMark.getLineNumber();
511             int column = startMark.getColumnNumber();
512
513             CharArrayWriter JavaDoc ttext = new CharArrayWriter JavaDoc();
514             int lastCh = 0, elType = 0;
515             for (int i = 0; i < charBuffer.length(); i++) {
516
517                 int ch = charBuffer.charAt(i);
518                 if (ch == '\n') {
519                     column = 1;
520                     line++;
521                 } else {
522                     column++;
523                 }
524                 if ((lastCh == '$' || lastCh == '#') && ch == '{') {
525                     elType = lastCh;
526                     if (ttext.size() > 0) {
527                         new Node.TemplateText(
528                             ttext.toString(),
529                             startMark,
530                             current);
531                         ttext = new CharArrayWriter JavaDoc();
532                         //We subtract two from the column number to
533
//account for the '[$,#]{' that we've already parsed
534
startMark = new Mark(ctxt, path, line, column - 2);
535                     }
536                     // following "${" || "#{" to first unquoted "}"
537
i++;
538                     boolean singleQ = false;
539                     boolean doubleQ = false;
540                     lastCh = 0;
541                     for (;; i++) {
542                         if (i >= charBuffer.length()) {
543                             throw new SAXParseException JavaDoc(
544                                 Localizer.getMessage(
545                                     "jsp.error.unterminated",
546                                     (char) elType + "{"),
547                                 locator);
548
549                         }
550                         ch = charBuffer.charAt(i);
551                         if (ch == '\n') {
552                             column = 1;
553                             line++;
554                         } else {
555                             column++;
556                         }
557                         if (lastCh == '\\' && (singleQ || doubleQ)) {
558                             ttext.write(ch);
559                             lastCh = 0;
560                             continue;
561                         }
562                         if (ch == '}') {
563                             new Node.ELExpression((char) elType,
564                                 ttext.toString(),
565                                 startMark,
566                                 current);
567                             ttext = new CharArrayWriter JavaDoc();
568                             startMark = new Mark(ctxt, path, line, column);
569                             break;
570                         }
571                         if (ch == '"')
572                             doubleQ = !doubleQ;
573                         else if (ch == '\'')
574                             singleQ = !singleQ;
575
576                         ttext.write(ch);
577                         lastCh = ch;
578                     }
579                 } else if (lastCh == '\\' && (ch == '$' || ch == '#')) {
580                     ttext.write(ch);
581                     ch = 0; // Not start of EL anymore
582
} else {
583                     if (lastCh == '$' || lastCh == '#' || lastCh == '\\') {
584                         ttext.write(lastCh);
585                     }
586                     if (ch != '$' && ch != '#' && ch != '\\') {
587                         ttext.write(ch);
588                     }
589                 }
590                 lastCh = ch;
591             }
592             if (lastCh == '$' || lastCh == '#' || lastCh == '\\') {
593                 ttext.write(lastCh);
594             }
595             if (ttext.size() > 0) {
596                 new Node.TemplateText(ttext.toString(), startMark, current);
597             }
598         }
599         startMark = new Mark(ctxt, path, locator.getLineNumber(),
600                              locator.getColumnNumber());
601
602         charBuffer = null;
603     }
604
605     /*
606      * Receives notification of the end of an element.
607      */

608     public void endElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc qName)
609         throws SAXException JavaDoc {
610
611         processChars();
612
613         if (directivesOnly &&
614             !(JSP_URI.equals(uri) && localName.startsWith(DIRECTIVE_ACTION))) {
615             return;
616         }
617
618         if (current instanceof Node.NamedAttribute) {
619             boolean isTrim = ((Node.NamedAttribute)current).isTrim();
620             Node.Nodes subElems = ((Node.NamedAttribute)current).getBody();
621             for (int i = 0; subElems != null && i < subElems.size(); i++) {
622                 Node subElem = subElems.getNode(i);
623                 if (!(subElem instanceof Node.TemplateText)) {
624                     continue;
625                 }
626                 // Ignore any whitespace (including spaces, carriage returns,
627
// line feeds, and tabs, that appear at the beginning and at
628
// the end of the body of the <jsp:attribute> action, if the
629
// action's 'trim' attribute is set to TRUE (default).
630
// In addition, any textual nodes in the <jsp:attribute> that
631
// have only white space are dropped from the document, with
632
// the exception of leading and trailing white-space-only
633
// textual nodes in a <jsp:attribute> whose 'trim' attribute
634
// is set to FALSE, which must be kept verbatim.
635
if (i == 0) {
636                     if (isTrim) {
637                         ((Node.TemplateText)subElem).ltrim();
638                     }
639                 } else if (i == subElems.size() - 1) {
640                     if (isTrim) {
641                         ((Node.TemplateText)subElem).rtrim();
642                     }
643                 } else {
644                     if (((Node.TemplateText)subElem).isAllSpace()) {
645                         subElems.remove(subElem);
646                     }
647                 }
648             }
649         } else if (current instanceof Node.ScriptingElement) {
650             checkScriptingBody((Node.ScriptingElement)current);
651         }
652
653         if ( isTagDependent(current)) {
654             tagDependentNesting--;
655         }
656
657         if (scriptlessBodyNode != null
658                 && current.equals(scriptlessBodyNode)) {
659             scriptlessBodyNode = null;
660         }
661
662         if (current.getParent() != null) {
663             current = current.getParent();
664         }
665     }
666
667     /*
668      * Receives the document locator.
669      *
670      * @param locator the document locator
671      */

672     public void setDocumentLocator(Locator JavaDoc locator) {
673         this.locator = locator;
674     }
675
676     /*
677      * See org.xml.sax.ext.LexicalHandler.
678      */

679     public void comment(char[] buf, int offset, int len) throws SAXException JavaDoc {
680
681         processChars(); // Flush char buffer and remove white spaces
682

683         // ignore comments in the DTD
684
if (!inDTD) {
685             startMark =
686                 new Mark(
687                     ctxt,
688                     path,
689                     locator.getLineNumber(),
690                     locator.getColumnNumber());
691             new Node.Comment(new String JavaDoc(buf, offset, len), startMark, current);
692         }
693     }
694
695     /*
696      * See org.xml.sax.ext.LexicalHandler.
697      */

698     public void startCDATA() throws SAXException JavaDoc {
699
700         processChars(); // Flush char buffer and remove white spaces
701
startMark = new Mark(ctxt, path, locator.getLineNumber(),
702                              locator.getColumnNumber());
703     }
704
705     /*
706      * See org.xml.sax.ext.LexicalHandler.
707      */

708     public void endCDATA() throws SAXException JavaDoc {
709         processChars(); // Flush char buffer and remove white spaces
710
}
711
712     /*
713      * See org.xml.sax.ext.LexicalHandler.
714      */

715     public void startEntity(String JavaDoc name) throws SAXException JavaDoc {
716         // do nothing
717
}
718
719     /*
720      * See org.xml.sax.ext.LexicalHandler.
721      */

722     public void endEntity(String JavaDoc name) throws SAXException JavaDoc {
723         // do nothing
724
}
725
726     /*
727      * See org.xml.sax.ext.LexicalHandler.
728      */

729     public void startDTD(String JavaDoc name, String JavaDoc publicId, String JavaDoc systemId)
730         throws SAXException JavaDoc {
731         if (!isValidating) {
732             fatalError(ENABLE_DTD_VALIDATION_EXCEPTION);
733         }
734
735         inDTD = true;
736     }
737
738     /*
739      * See org.xml.sax.ext.LexicalHandler.
740      */

741     public void endDTD() throws SAXException JavaDoc {
742         inDTD = false;
743     }
744
745     /*
746      * Receives notification of a non-recoverable error.
747      */

748     public void fatalError(SAXParseException JavaDoc e) throws SAXException JavaDoc {
749         throw e;
750     }
751
752     /*
753      * Receives notification of a recoverable error.
754      */

755     public void error(SAXParseException JavaDoc e) throws SAXException JavaDoc {
756         throw e;
757     }
758
759     /*
760      * Receives notification of the start of a Namespace mapping.
761      */

762     public void startPrefixMapping(String JavaDoc prefix, String JavaDoc uri)
763         throws SAXException JavaDoc {
764         TagLibraryInfo JavaDoc taglibInfo;
765
766         if (directivesOnly && !(JSP_URI.equals(uri))) {
767             return;
768         }
769         
770         try {
771             taglibInfo = getTaglibInfo(prefix, uri);
772         } catch (JasperException je) {
773             throw new SAXParseException JavaDoc(
774                 Localizer.getMessage("jsp.error.could.not.add.taglibraries"),
775                 locator,
776                 je);
777         }
778
779         if (taglibInfo != null) {
780             if (pageInfo.getTaglib(uri) == null) {
781                 pageInfo.addTaglib(uri, taglibInfo);
782             }
783             pageInfo.pushPrefixMapping(prefix, uri);
784         } else {
785             pageInfo.pushPrefixMapping(prefix, null);
786         }
787     }
788
789     /*
790      * Receives notification of the end of a Namespace mapping.
791      */

792     public void endPrefixMapping(String JavaDoc prefix) throws SAXException JavaDoc {
793
794         if (directivesOnly) {
795             String JavaDoc uri = pageInfo.getURI(prefix);
796             if (!JSP_URI.equals(uri)) {
797                 return;
798             }
799         }
800
801         pageInfo.popPrefixMapping(prefix);
802     }
803
804     //*********************************************************************
805
// Private utility methods
806

807     private Node parseStandardAction(
808         String JavaDoc qName,
809         String JavaDoc localName,
810         Attributes JavaDoc nonTaglibAttrs,
811         Attributes JavaDoc nonTaglibXmlnsAttrs,
812         Attributes JavaDoc taglibAttrs,
813         Mark start,
814         Node parent)
815         throws SAXException JavaDoc {
816
817         Node node = null;
818
819         if (localName.equals(ROOT_ACTION)) {
820             if (!(current instanceof Node.Root)) {
821                 throw new SAXParseException JavaDoc(
822                     Localizer.getMessage("jsp.error.nested_jsproot"),
823                     locator);
824             }
825             node =
826                 new Node.JspRoot(
827                     qName,
828                     nonTaglibAttrs,
829                     nonTaglibXmlnsAttrs,
830                     taglibAttrs,
831                     start,
832                     current);
833             if (isTop) {
834                 pageInfo.setHasJspRoot(true);
835             }
836         } else if (localName.equals(PAGE_DIRECTIVE_ACTION)) {
837             if (isTagFile) {
838                 throw new SAXParseException JavaDoc(
839                     Localizer.getMessage(
840                         "jsp.error.action.istagfile",
841                         localName),
842                     locator);
843             }
844             node =
845                 new Node.PageDirective(
846                     qName,
847                     nonTaglibAttrs,
848                     nonTaglibXmlnsAttrs,
849                     taglibAttrs,
850                     start,
851                     current);
852             String JavaDoc imports = nonTaglibAttrs.getValue("import");
853             // There can only be one 'import' attribute per page directive
854
if (imports != null) {
855                 ((Node.PageDirective)node).addImport(imports);
856             }
857         } else if (localName.equals(INCLUDE_DIRECTIVE_ACTION)) {
858             node =
859                 new Node.IncludeDirective(
860                     qName,
861                     nonTaglibAttrs,
862                     nonTaglibXmlnsAttrs,
863                     taglibAttrs,
864                     start,
865                     current);
866             processIncludeDirective(nonTaglibAttrs.getValue("file"), node);
867         } else if (localName.equals(DECLARATION_ACTION)) {
868             if (scriptlessBodyNode != null) {
869                 // We're nested inside a node whose body is
870
// declared to be scriptless
871
throw new SAXParseException JavaDoc(
872                     Localizer.getMessage(
873                         "jsp.error.no.scriptlets",
874                         localName),
875                     locator);
876             }
877             node =
878                 new Node.Declaration(
879                     qName,
880                     nonTaglibXmlnsAttrs,
881                     taglibAttrs,
882                     start,
883                     current);
884         } else if (localName.equals(SCRIPTLET_ACTION)) {
885             if (scriptlessBodyNode != null) {
886                 // We're nested inside a node whose body is
887
// declared to be scriptless
888
throw new SAXParseException JavaDoc(
889                     Localizer.getMessage(
890                         "jsp.error.no.scriptlets",
891                         localName),
892                     locator);
893             }
894             node =
895                 new Node.Scriptlet(
896                     qName,
897                     nonTaglibXmlnsAttrs,
898                     taglibAttrs,
899                     start,
900                     current);
901         } else if (localName.equals(EXPRESSION_ACTION)) {
902             if (scriptlessBodyNode != null) {
903                 // We're nested inside a node whose body is
904
// declared to be scriptless
905
throw new SAXParseException JavaDoc(
906                     Localizer.getMessage(
907                         "jsp.error.no.scriptlets",
908                         localName),
909                     locator);
910             }
911             node =
912                 new Node.Expression(
913                     qName,
914                     nonTaglibXmlnsAttrs,
915                     taglibAttrs,
916                     start,
917                     current);
918         } else if (localName.equals(USE_BEAN_ACTION)) {
919             node =
920                 new Node.UseBean(
921                     qName,
922                     nonTaglibAttrs,
923                     nonTaglibXmlnsAttrs,
924                     taglibAttrs,
925                     start,
926                     current);
927         } else if (localName.equals(SET_PROPERTY_ACTION)) {
928             node =
929                 new Node.SetProperty(
930                     qName,
931                     nonTaglibAttrs,
932                     nonTaglibXmlnsAttrs,
933                     taglibAttrs,
934                     start,
935                     current);
936         } else if (localName.equals(GET_PROPERTY_ACTION)) {
937             node =
938                 new Node.GetProperty(
939                     qName,
940                     nonTaglibAttrs,
941                     nonTaglibXmlnsAttrs,
942                     taglibAttrs,
943                     start,
944                     current);
945         } else if (localName.equals(INCLUDE_ACTION)) {
946             node =
947                 new Node.IncludeAction(
948                     qName,
949                     nonTaglibAttrs,
950                     nonTaglibXmlnsAttrs,
951                     taglibAttrs,
952                     start,
953                     current);
954         } else if (localName.equals(FORWARD_ACTION)) {
955             node =
956                 new Node.ForwardAction(
957                     qName,
958                     nonTaglibAttrs,
959                     nonTaglibXmlnsAttrs,
960                     taglibAttrs,
961                     start,
962                     current);
963         } else if (localName.equals(PARAM_ACTION)) {
964             node =
965                 new Node.ParamAction(
966                     qName,
967                     nonTaglibAttrs,
968                     nonTaglibXmlnsAttrs,
969                     taglibAttrs,
970                     start,
971                     current);
972         } else if (localName.equals(PARAMS_ACTION)) {
973             node =
974                 new Node.ParamsAction(
975                     qName,
976                     nonTaglibXmlnsAttrs,
977                     taglibAttrs,
978                     start,
979                     current);
980         } else if (localName.equals(PLUGIN_ACTION)) {
981             node =
982                 new Node.PlugIn(
983                     qName,
984                     nonTaglibAttrs,
985                     nonTaglibXmlnsAttrs,
986                     taglibAttrs,
987                     start,
988                     current);
989         } else if (localName.equals(TEXT_ACTION)) {
990             node =
991                 new Node.JspText(
992                     qName,
993                     nonTaglibXmlnsAttrs,
994                     taglibAttrs,
995                     start,
996                     current);
997         } else if (localName.equals(BODY_ACTION)) {
998             node =
999                 new Node.JspBody(
1000                    qName,
1001                    nonTaglibXmlnsAttrs,
1002                    taglibAttrs,
1003                    start,
1004                    current);
1005        } else if (localName.equals(ATTRIBUTE_ACTION)) {
1006            node =
1007                new Node.NamedAttribute(
1008                    qName,
1009                    nonTaglibAttrs,
1010                    nonTaglibXmlnsAttrs,
1011                    taglibAttrs,
1012                    start,
1013                    current);
1014        } else if (localName.equals(OUTPUT_ACTION)) {
1015            node =
1016                new Node.JspOutput(
1017                    qName,
1018                    nonTaglibAttrs,
1019                    nonTaglibXmlnsAttrs,
1020                    taglibAttrs,
1021                    start,
1022                    current);
1023        } else if (localName.equals(TAG_DIRECTIVE_ACTION)) {
1024            if (!isTagFile) {
1025                throw new SAXParseException JavaDoc(
1026                    Localizer.getMessage(
1027                        "jsp.error.action.isnottagfile",
1028                        localName),
1029                    locator);
1030            }
1031            node =
1032                new Node.TagDirective(
1033                    qName,
1034                    nonTaglibAttrs,
1035                    nonTaglibXmlnsAttrs,
1036                    taglibAttrs,
1037                    start,
1038                    current);
1039            String JavaDoc imports = nonTaglibAttrs.getValue("import");
1040            // There can only be one 'import' attribute per tag directive
1041
if (imports != null) {
1042                ((Node.TagDirective)node).addImport(imports);
1043            }
1044        } else if (localName.equals(ATTRIBUTE_DIRECTIVE_ACTION)) {
1045            if (!isTagFile) {
1046                throw new SAXParseException JavaDoc(
1047                    Localizer.getMessage(
1048                        "jsp.error.action.isnottagfile",
1049                        localName),
1050                    locator);
1051            }
1052            node =
1053                new Node.AttributeDirective(
1054                    qName,
1055                    nonTaglibAttrs,
1056                    nonTaglibXmlnsAttrs,
1057                    taglibAttrs,
1058                    start,
1059                    current);
1060        } else if (localName.equals(VARIABLE_DIRECTIVE_ACTION)) {
1061            if (!isTagFile) {
1062                throw new SAXParseException JavaDoc(
1063                    Localizer.getMessage(
1064                        "jsp.error.action.isnottagfile",
1065                        localName),
1066                    locator);
1067            }
1068            node =
1069                new Node.VariableDirective(
1070                    qName,
1071                    nonTaglibAttrs,
1072                    nonTaglibXmlnsAttrs,
1073                    taglibAttrs,
1074                    start,
1075                    current);
1076        } else if (localName.equals(INVOKE_ACTION)) {
1077            if (!isTagFile) {
1078                throw new SAXParseException JavaDoc(
1079                    Localizer.getMessage(
1080                        "jsp.error.action.isnottagfile",
1081                        localName),
1082                    locator);
1083            }
1084            node =
1085                new Node.InvokeAction(
1086                    qName,
1087                    nonTaglibAttrs,
1088                    nonTaglibXmlnsAttrs,
1089                    taglibAttrs,
1090                    start,
1091                    current);
1092        } else if (localName.equals(DOBODY_ACTION)) {
1093            if (!isTagFile) {
1094                throw new SAXParseException JavaDoc(
1095                    Localizer.getMessage(
1096                        "jsp.error.action.isnottagfile",
1097                        localName),
1098                    locator);
1099            }
1100            node =
1101                new Node.DoBodyAction(
1102                    qName,
1103                    nonTaglibAttrs,
1104                    nonTaglibXmlnsAttrs,
1105                    taglibAttrs,
1106                    start,
1107                    current);
1108        } else if (localName.equals(ELEMENT_ACTION)) {
1109            node =
1110                new Node.JspElement(
1111                    qName,
1112                    nonTaglibAttrs,
1113                    nonTaglibXmlnsAttrs,
1114                    taglibAttrs,
1115                    start,
1116                    current);
1117        } else if (localName.equals(FALLBACK_ACTION)) {
1118            node =
1119                new Node.FallBackAction(
1120                    qName,
1121                    nonTaglibXmlnsAttrs,
1122                    taglibAttrs,
1123                    start,
1124                    current);
1125        } else {
1126            throw new SAXParseException JavaDoc(
1127                Localizer.getMessage(
1128                    "jsp.error.xml.badStandardAction",
1129                    localName),
1130                locator);
1131        }
1132
1133        return node;
1134    }
1135
1136    /*
1137     * Checks if the XML element with the given tag name is a custom action,
1138     * and returns the corresponding Node object.
1139     */

1140    private Node parseCustomAction(
1141        String JavaDoc qName,
1142        String JavaDoc localName,
1143        String JavaDoc uri,
1144        Attributes JavaDoc nonTaglibAttrs,
1145        Attributes JavaDoc nonTaglibXmlnsAttrs,
1146        Attributes JavaDoc taglibAttrs,
1147        Mark start,
1148        Node parent)
1149        throws SAXException JavaDoc {
1150
1151        // Check if this is a user-defined (custom) tag
1152
TagLibraryInfo JavaDoc tagLibInfo = pageInfo.getTaglib(uri);
1153        if (tagLibInfo == null) {
1154            return null;
1155        }
1156
1157        TagInfo JavaDoc tagInfo = tagLibInfo.getTag(localName);
1158        TagFileInfo JavaDoc tagFileInfo = tagLibInfo.getTagFile(localName);
1159        if (tagInfo == null && tagFileInfo == null) {
1160            throw new SAXException JavaDoc(
1161                Localizer.getMessage("jsp.error.xml.bad_tag", localName, uri));
1162        }
1163        Class JavaDoc tagHandlerClass = null;
1164        if (tagInfo != null) {
1165            String JavaDoc handlerClassName = tagInfo.getTagClassName();
1166            try {
1167                tagHandlerClass =
1168                    ctxt.getClassLoader().loadClass(handlerClassName);
1169            } catch (Exception JavaDoc e) {
1170                throw new SAXException JavaDoc(
1171                    Localizer.getMessage("jsp.error.loadclass.taghandler",
1172                                         handlerClassName,
1173                                         qName),
1174                    e);
1175            }
1176        }
1177
1178        String JavaDoc prefix = "";
1179        int colon = qName.indexOf(':');
1180        if (colon != -1) {
1181            prefix = qName.substring(0, colon);
1182        }
1183
1184        Node.CustomTag ret = null;
1185        if (tagInfo != null) {
1186            ret =
1187                new Node.CustomTag(
1188                    qName,
1189                    prefix,
1190                    localName,
1191                    uri,
1192                    nonTaglibAttrs,
1193                    nonTaglibXmlnsAttrs,
1194                    taglibAttrs,
1195                    start,
1196                    parent,
1197                    tagInfo,
1198                    tagHandlerClass);
1199        } else {
1200            ret =
1201                new Node.CustomTag(
1202                    qName,
1203                    prefix,
1204                    localName,
1205                    uri,
1206                    nonTaglibAttrs,
1207                    nonTaglibXmlnsAttrs,
1208                    taglibAttrs,
1209                    start,
1210                    parent,
1211                    tagFileInfo);
1212        }
1213
1214        return ret;
1215    }
1216
1217    /*
1218     * Creates the tag library associated with the given uri namespace, and
1219     * returns it.
1220     *
1221     * @param prefix The prefix of the xmlns attribute
1222     * @param uri The uri namespace (value of the xmlns attribute)
1223     *
1224     * @return The tag library associated with the given uri namespace
1225     */

1226    private TagLibraryInfo JavaDoc getTaglibInfo(String JavaDoc prefix, String JavaDoc uri)
1227        throws JasperException {
1228
1229        TagLibraryInfo JavaDoc result = null;
1230
1231        if (uri.startsWith(URN_JSPTAGDIR)) {
1232            // uri (of the form "urn:jsptagdir:path") references tag file dir
1233
String JavaDoc tagdir = uri.substring(URN_JSPTAGDIR.length());
1234            result =
1235                new ImplicitTagLibraryInfo(
1236                    ctxt,
1237                    parserController,
1238                    pageInfo,
1239                    prefix,
1240                    tagdir,
1241                    err);
1242        } else {
1243            // uri references TLD file
1244
boolean isPlainUri = false;
1245            if (uri.startsWith(URN_JSPTLD)) {
1246                // uri is of the form "urn:jsptld:path"
1247
uri = uri.substring(URN_JSPTLD.length());
1248            } else {
1249                isPlainUri = true;
1250            }
1251
1252            String JavaDoc[] location = ctxt.getTldLocation(uri);
1253            if (location != null || !isPlainUri) {
1254                if (ctxt.getOptions().isCaching()) {
1255                    result = (TagLibraryInfoImpl) ctxt.getOptions().getCache().get(uri);
1256                }
1257                if (result == null) {
1258                    /*
1259                     * If the uri value is a plain uri, a translation error must
1260                     * not be generated if the uri is not found in the taglib map.
1261                     * Instead, any actions in the namespace defined by the uri
1262                     * value must be treated as uninterpreted.
1263                     */

1264                    result =
1265                        new TagLibraryInfoImpl(
1266                            ctxt,
1267                            parserController,
1268                            pageInfo,
1269                            prefix,
1270                            uri,
1271                            location,
1272                            err);
1273                    if (ctxt.getOptions().isCaching()) {
1274                        ctxt.getOptions().getCache().put(uri, result);
1275                    }
1276                }
1277            }
1278        }
1279
1280        return result;
1281    }
1282
1283    /*
1284     * Ensures that the given body only contains nodes that are instances of
1285     * TemplateText.
1286     *
1287     * This check is performed only for the body of a scripting (that is:
1288     * declaration, scriptlet, or expression) element, after the end tag of a
1289     * scripting element has been reached.
1290     */

1291    private void checkScriptingBody(Node.ScriptingElement scriptingElem)
1292        throws SAXException JavaDoc {
1293        Node.Nodes body = scriptingElem.getBody();
1294        if (body != null) {
1295            int size = body.size();
1296            for (int i = 0; i < size; i++) {
1297                Node n = body.getNode(i);
1298                if (!(n instanceof Node.TemplateText)) {
1299                    String JavaDoc elemType = SCRIPTLET_ACTION;
1300                    if (scriptingElem instanceof Node.Declaration)
1301                        elemType = DECLARATION_ACTION;
1302                    if (scriptingElem instanceof Node.Expression)
1303                        elemType = EXPRESSION_ACTION;
1304                    String JavaDoc msg =
1305                        Localizer.getMessage(
1306                            "jsp.error.parse.xml.scripting.invalid.body",
1307                            elemType);
1308                    throw new SAXException JavaDoc(msg);
1309                }
1310            }
1311        }
1312    }
1313
1314    /*
1315     * Parses the given file included via an include directive.
1316     *
1317     * @param fname The path to the included resource, as specified by the
1318     * 'file' attribute of the include directive
1319     * @param parent The Node representing the include directive
1320     */

1321    private void processIncludeDirective(String JavaDoc fname, Node parent)
1322        throws SAXException JavaDoc {
1323
1324        if (fname == null) {
1325            return;
1326        }
1327
1328        try {
1329            parserController.parse(fname, parent, null);
1330        } catch (FileNotFoundException JavaDoc fnfe) {
1331            throw new SAXParseException JavaDoc(
1332                Localizer.getMessage("jsp.error.file.not.found", fname),
1333                locator,
1334                fnfe);
1335        } catch (Exception JavaDoc e) {
1336            throw new SAXException JavaDoc(e);
1337        }
1338    }
1339
1340    /*
1341     * Checks an element's given URI, qname, and attributes to see if any
1342     * of them hijack the 'jsp' prefix, that is, bind it to a namespace other
1343     * than http://java.sun.com/JSP/Page.
1344     *
1345     * @param uri The element's URI
1346     * @param qName The element's qname
1347     * @param attrs The element's attributes
1348     */

1349    private void checkPrefixes(String JavaDoc uri, String JavaDoc qName, Attributes JavaDoc attrs) {
1350
1351        checkPrefix(uri, qName);
1352
1353        int len = attrs.getLength();
1354        for (int i = 0; i < len; i++) {
1355            checkPrefix(attrs.getURI(i), attrs.getQName(i));
1356        }
1357    }
1358
1359    /*
1360     * Checks the given URI and qname to see if they hijack the 'jsp' prefix,
1361     * which would be the case if qName contained the 'jsp' prefix and
1362     * uri was different from http://java.sun.com/JSP/Page.
1363     *
1364     * @param uri The URI to check
1365     * @param qName The qname to check
1366     */

1367    private void checkPrefix(String JavaDoc uri, String JavaDoc qName) {
1368
1369        int index = qName.indexOf(':');
1370        if (index != -1) {
1371            String JavaDoc prefix = qName.substring(0, index);
1372            pageInfo.addPrefix(prefix);
1373            if ("jsp".equals(prefix) && !JSP_URI.equals(uri)) {
1374                pageInfo.setIsJspPrefixHijacked(true);
1375            }
1376        }
1377    }
1378
1379    /*
1380     * Gets SAXParser.
1381     *
1382     * @param validating Indicates whether the requested SAXParser should
1383     * be validating
1384     * @param jspDocParser The JSP document parser
1385     *
1386     * @return The SAXParser
1387     */

1388    private static SAXParser JavaDoc getSAXParser(
1389        boolean validating,
1390        JspDocumentParser jspDocParser)
1391        throws Exception JavaDoc {
1392
1393        SAXParserFactory JavaDoc factory = SAXParserFactory.newInstance();
1394        factory.setNamespaceAware(true);
1395
1396        // Preserve xmlns attributes
1397
factory.setFeature(
1398            "http://xml.org/sax/features/namespace-prefixes",
1399            true);
1400        factory.setValidating(validating);
1401        //factory.setFeature(
1402
// "http://xml.org/sax/features/validation",
1403
// validating);
1404

1405        // Configure the parser
1406
SAXParser JavaDoc saxParser = factory.newSAXParser();
1407        XMLReader JavaDoc xmlReader = saxParser.getXMLReader();
1408        xmlReader.setProperty(LEXICAL_HANDLER_PROPERTY, jspDocParser);
1409        xmlReader.setErrorHandler(jspDocParser);
1410
1411        return saxParser;
1412    }
1413
1414    /*
1415     * Exception indicating that a DOCTYPE declaration is present, but
1416     * validation is turned off.
1417     */

1418    private static class EnableDTDValidationException
1419        extends SAXParseException JavaDoc {
1420
1421        EnableDTDValidationException(String JavaDoc message, Locator JavaDoc loc) {
1422            super(message, loc);
1423        }
1424    }
1425
1426    private static String JavaDoc getBodyType(Node.CustomTag custom) {
1427
1428        if (custom.getTagInfo() != null) {
1429            return custom.getTagInfo().getBodyContent();
1430        }
1431
1432        return custom.getTagFileInfo().getTagInfo().getBodyContent();
1433    }
1434
1435    private boolean isTagDependent(Node n) {
1436
1437        if (n instanceof Node.CustomTag) {
1438            String JavaDoc bodyType = getBodyType((Node.CustomTag) n);
1439            return
1440                TagInfo.BODY_CONTENT_TAG_DEPENDENT.equalsIgnoreCase(bodyType);
1441        }
1442        return false;
1443    }
1444}
1445
Popular Tags