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

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


001:        /*
002:         * Licensed to the Apache Software Foundation (ASF) under one or more
003:         * contributor license agreements.  See the NOTICE file distributed with
004:         * this work for additional information regarding copyright ownership.
005:         * The ASF licenses this file to You under the Apache License, Version 2.0
006:         * (the "License"); you may not use this file except in compliance with
007:         * the License.  You may obtain a copy of the License at
008:         * 
009:         *      http://www.apache.org/licenses/LICENSE-2.0
010:         * 
011:         * Unless required by applicable law or agreed to in writing, software
012:         * distributed under the License is distributed on an "AS IS" BASIS,
013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         * See the License for the specific language governing permissions and
015:         * limitations under the License.
016:         */
017:
018:        package org.apache.jasper.compiler;
019:
020:        import java.io.CharArrayWriter;
021:        import java.io.FileNotFoundException;
022:        import java.io.IOException;
023:        import java.io.InputStreamReader;
024:        import java.util.List;
025:        import java.util.Vector;
026:        import java.util.jar.JarFile;
027:        import java.net.URL;
028:        import java.net.MalformedURLException;
029:
030:        import org.apache.jasper.JasperException;
031:        import org.apache.jasper.JspCompilationContext;
032:        import org.apache.juli.logging.Log;
033:        import org.apache.juli.logging.LogFactory;
034:
035:        /**
036:         * JspReader is an input buffer for the JSP parser. It should allow
037:         * unlimited lookahead and pushback. It also has a bunch of parsing
038:         * utility methods for understanding htmlesque thingies.
039:         *
040:         * @author Anil K. Vijendran
041:         * @author Anselm Baird-Smith
042:         * @author Harish Prabandham
043:         * @author Rajiv Mordani
044:         * @author Mandar Raje
045:         * @author Danno Ferrin
046:         * @author Kin-man Chung
047:         * @author Shawn Bayern
048:         * @author Mark Roth
049:         */
050:
051:        class JspReader {
052:
053:            /**
054:             * Logger.
055:             */
056:            private Log log = LogFactory.getLog(JspReader.class);
057:
058:            /**
059:             * The current spot in the file.
060:             */
061:            private Mark current;
062:
063:            /**
064:             * What is this?
065:             */
066:            private String master;
067:
068:            /**
069:             * The list of source files.
070:             */
071:            private List sourceFiles;
072:
073:            /**
074:             * The current file ID (-1 indicates an error or no file).
075:             */
076:            private int currFileId;
077:
078:            /**
079:             * Seems redundant.
080:             */
081:            private int size;
082:
083:            /**
084:             * The compilation context.
085:             */
086:            private JspCompilationContext context;
087:
088:            /**
089:             * The Jasper error dispatcher.
090:             */
091:            private ErrorDispatcher err;
092:
093:            /**
094:             * Set to true when using the JspReader on a single file where we read up
095:             * to the end and reset to the beginning many times.
096:             * (as in ParserController.figureOutJspDocument()).
097:             */
098:            private boolean singleFile;
099:
100:            /**
101:             * Constructor.
102:             *
103:             * @param ctxt The compilation context
104:             * @param fname The file name
105:             * @param encoding The file encoding
106:             * @param jarFile ?
107:             * @param err The error dispatcher
108:             * @throws JasperException If a Jasper-internal error occurs
109:             * @throws FileNotFoundException If the JSP file is not found (or is unreadable)
110:             * @throws IOException If an IO-level error occurs, e.g. reading the file
111:             */
112:            public JspReader(JspCompilationContext ctxt, String fname,
113:                    String encoding, JarFile jarFile, ErrorDispatcher err)
114:                    throws JasperException, FileNotFoundException, IOException {
115:
116:                this (ctxt, fname, encoding, JspUtil.getReader(fname, encoding,
117:                        jarFile, ctxt, err), err);
118:            }
119:
120:            /**
121:             * Constructor: same as above constructor but with initialized reader
122:             * to the file given.
123:             */
124:            public JspReader(JspCompilationContext ctxt, String fname,
125:                    String encoding, InputStreamReader reader,
126:                    ErrorDispatcher err) throws JasperException,
127:                    FileNotFoundException {
128:
129:                this .context = ctxt;
130:                this .err = err;
131:                sourceFiles = new Vector();
132:                currFileId = 0;
133:                size = 0;
134:                singleFile = false;
135:                pushFile(fname, encoding, reader);
136:            }
137:
138:            /**
139:             * @return JSP compilation context with which this JspReader is 
140:             * associated
141:             */
142:            JspCompilationContext getJspCompilationContext() {
143:                return context;
144:            }
145:
146:            /**
147:             * Returns the file at the given position in the list.
148:             *
149:             * @param fileid The file position in the list
150:             * @return The file at that position, if found, null otherwise
151:             */
152:            String getFile(final int fileid) {
153:                return (String) sourceFiles.get(fileid);
154:            }
155:
156:            /**
157:             * Checks if the current file has more input.
158:             *
159:             * @return True if more reading is possible
160:             * @throws JasperException if an error occurs
161:             */
162:            boolean hasMoreInput() throws JasperException {
163:                if (current.cursor >= current.stream.length) {
164:                    if (singleFile)
165:                        return false;
166:                    while (popFile()) {
167:                        if (current.cursor < current.stream.length)
168:                            return true;
169:                    }
170:                    return false;
171:                }
172:                return true;
173:            }
174:
175:            int nextChar() throws JasperException {
176:                if (!hasMoreInput())
177:                    return -1;
178:
179:                int ch = current.stream[current.cursor];
180:
181:                current.cursor++;
182:
183:                if (ch == '\n') {
184:                    current.line++;
185:                    current.col = 0;
186:                } else {
187:                    current.col++;
188:                }
189:                return ch;
190:            }
191:
192:            /**
193:             * Back up the current cursor by one char, assumes current.cursor > 0,
194:             * and that the char to be pushed back is not '\n'.
195:             */
196:            void pushChar() {
197:                current.cursor--;
198:                current.col--;
199:            }
200:
201:            String getText(Mark start, Mark stop) throws JasperException {
202:                Mark oldstart = mark();
203:                reset(start);
204:                CharArrayWriter caw = new CharArrayWriter();
205:                while (!stop.equals(mark()))
206:                    caw.write(nextChar());
207:                caw.close();
208:                reset(oldstart);
209:                return caw.toString();
210:            }
211:
212:            int peekChar() throws JasperException {
213:                if (!hasMoreInput())
214:                    return -1;
215:                return current.stream[current.cursor];
216:            }
217:
218:            Mark mark() {
219:                return new Mark(current);
220:            }
221:
222:            void reset(Mark mark) {
223:                current = new Mark(mark);
224:            }
225:
226:            boolean matchesIgnoreCase(String string) throws JasperException {
227:                Mark mark = mark();
228:                int ch = 0;
229:                int i = 0;
230:                do {
231:                    ch = nextChar();
232:                    if (Character.toLowerCase((char) ch) != string.charAt(i++)) {
233:                        reset(mark);
234:                        return false;
235:                    }
236:                } while (i < string.length());
237:                reset(mark);
238:                return true;
239:            }
240:
241:            /**
242:             * search the stream for a match to a string
243:             * @param string The string to match
244:             * @return <strong>true</strong> is one is found, the current position
245:             *         in stream is positioned after the search string, <strong>
246:             *               false</strong> otherwise, position in stream unchanged.
247:             */
248:            boolean matches(String string) throws JasperException {
249:                Mark mark = mark();
250:                int ch = 0;
251:                int i = 0;
252:                do {
253:                    ch = nextChar();
254:                    if (((char) ch) != string.charAt(i++)) {
255:                        reset(mark);
256:                        return false;
257:                    }
258:                } while (i < string.length());
259:                return true;
260:            }
261:
262:            boolean matchesETag(String tagName) throws JasperException {
263:                Mark mark = mark();
264:
265:                if (!matches("</" + tagName))
266:                    return false;
267:                skipSpaces();
268:                if (nextChar() == '>')
269:                    return true;
270:
271:                reset(mark);
272:                return false;
273:            }
274:
275:            boolean matchesETagWithoutLessThan(String tagName)
276:                    throws JasperException {
277:                Mark mark = mark();
278:
279:                if (!matches("/" + tagName))
280:                    return false;
281:                skipSpaces();
282:                if (nextChar() == '>')
283:                    return true;
284:
285:                reset(mark);
286:                return false;
287:            }
288:
289:            /**
290:             * Looks ahead to see if there are optional spaces followed by
291:             * the given String.  If so, true is returned and those spaces and
292:             * characters are skipped.  If not, false is returned and the
293:             * position is restored to where we were before.
294:             */
295:            boolean matchesOptionalSpacesFollowedBy(String s)
296:                    throws JasperException {
297:                Mark mark = mark();
298:
299:                skipSpaces();
300:                boolean result = matches(s);
301:                if (!result) {
302:                    reset(mark);
303:                }
304:
305:                return result;
306:            }
307:
308:            int skipSpaces() throws JasperException {
309:                int i = 0;
310:                while (hasMoreInput() && isSpace()) {
311:                    i++;
312:                    nextChar();
313:                }
314:                return i;
315:            }
316:
317:            /**
318:             * Skip until the given string is matched in the stream.
319:             * When returned, the context is positioned past the end of the match.
320:             *
321:             * @param s The String to match.
322:             * @return A non-null <code>Mark</code> instance (positioned immediately
323:             *         before the search string) if found, <strong>null</strong>
324:             *         otherwise.
325:             */
326:            Mark skipUntil(String limit) throws JasperException {
327:                Mark ret = null;
328:                int limlen = limit.length();
329:                int ch;
330:
331:                skip: for (ret = mark(), ch = nextChar(); ch != -1; ret = mark(), ch = nextChar()) {
332:                    if (ch == limit.charAt(0)) {
333:                        Mark restart = mark();
334:                        for (int i = 1; i < limlen; i++) {
335:                            if (peekChar() == limit.charAt(i))
336:                                nextChar();
337:                            else {
338:                                reset(restart);
339:                                continue skip;
340:                            }
341:                        }
342:                        return ret;
343:                    }
344:                }
345:                return null;
346:            }
347:
348:            /**
349:             * Skip until the given string is matched in the stream, but ignoring
350:             * chars initially escaped by a '\'.
351:             * When returned, the context is positioned past the end of the match.
352:             *
353:             * @param s The String to match.
354:             * @return A non-null <code>Mark</code> instance (positioned immediately
355:             *         before the search string) if found, <strong>null</strong>
356:             *         otherwise.
357:             */
358:            Mark skipUntilIgnoreEsc(String limit) throws JasperException {
359:                Mark ret = null;
360:                int limlen = limit.length();
361:                int ch;
362:                int prev = 'x'; // Doesn't matter
363:
364:                skip: for (ret = mark(), ch = nextChar(); ch != -1; ret = mark(), prev = ch, ch = nextChar()) {
365:                    if (ch == '\\' && prev == '\\') {
366:                        ch = 0; // Double \ is not an escape char anymore
367:                    } else if (ch == limit.charAt(0) && prev != '\\') {
368:                        for (int i = 1; i < limlen; i++) {
369:                            if (peekChar() == limit.charAt(i))
370:                                nextChar();
371:                            else
372:                                continue skip;
373:                        }
374:                        return ret;
375:                    }
376:                }
377:                return null;
378:            }
379:
380:            /**
381:             * Skip until the given end tag is matched in the stream.
382:             * When returned, the context is positioned past the end of the tag.
383:             *
384:             * @param tag The name of the tag whose ETag (</tag>) to match.
385:             * @return A non-null <code>Mark</code> instance (positioned immediately
386:             *               before the ETag) if found, <strong>null</strong> otherwise.
387:             */
388:            Mark skipUntilETag(String tag) throws JasperException {
389:                Mark ret = skipUntil("</" + tag);
390:                if (ret != null) {
391:                    skipSpaces();
392:                    if (nextChar() != '>')
393:                        ret = null;
394:                }
395:                return ret;
396:            }
397:
398:            final boolean isSpace() throws JasperException {
399:                // Note: If this logic changes, also update Node.TemplateText.rtrim()
400:                return peekChar() <= ' ';
401:            }
402:
403:            /**
404:             * Parse a space delimited token.
405:             * If quoted the token will consume all characters up to a matching quote,
406:             * otherwise, it consumes up to the first delimiter character.
407:             *
408:             * @param quoted If <strong>true</strong> accept quoted strings.
409:             */
410:            String parseToken(boolean quoted) throws JasperException {
411:                StringBuffer stringBuffer = new StringBuffer();
412:                skipSpaces();
413:                stringBuffer.setLength(0);
414:
415:                if (!hasMoreInput()) {
416:                    return "";
417:                }
418:
419:                int ch = peekChar();
420:
421:                if (quoted) {
422:                    if (ch == '"' || ch == '\'') {
423:
424:                        char endQuote = ch == '"' ? '"' : '\'';
425:                        // Consume the open quote: 
426:                        ch = nextChar();
427:                        for (ch = nextChar(); ch != -1 && ch != endQuote; ch = nextChar()) {
428:                            if (ch == '\\')
429:                                ch = nextChar();
430:                            stringBuffer.append((char) ch);
431:                        }
432:                        // Check end of quote, skip closing quote:
433:                        if (ch == -1) {
434:                            err.jspError(mark(),
435:                                    "jsp.error.quotes.unterminated");
436:                        }
437:                    } else {
438:                        err.jspError(mark(), "jsp.error.attr.quoted");
439:                    }
440:                } else {
441:                    if (!isDelimiter()) {
442:                        // Read value until delimiter is found:
443:                        do {
444:                            ch = nextChar();
445:                            // Take care of the quoting here.
446:                            if (ch == '\\') {
447:                                if (peekChar() == '"' || peekChar() == '\''
448:                                        || peekChar() == '>'
449:                                        || peekChar() == '%')
450:                                    ch = nextChar();
451:                            }
452:                            stringBuffer.append((char) ch);
453:                        } while (!isDelimiter());
454:                    }
455:                }
456:
457:                return stringBuffer.toString();
458:            }
459:
460:            void setSingleFile(boolean val) {
461:                singleFile = val;
462:            }
463:
464:            /**
465:             * Gets the URL for the given path name.
466:             *
467:             * @param path Path name
468:             *
469:             * @return URL for the given path name.
470:             *
471:             * @exception MalformedURLException if the path name is not given in 
472:             * the correct form
473:             */
474:            URL getResource(String path) throws MalformedURLException {
475:                return context.getResource(path);
476:            }
477:
478:            /**
479:             * Parse utils - Is current character a token delimiter ?
480:             * Delimiters are currently defined to be =, &gt;, &lt;, ", and ' or any
481:             * any space character as defined by <code>isSpace</code>.
482:             *
483:             * @return A boolean.
484:             */
485:            private boolean isDelimiter() throws JasperException {
486:                if (!isSpace()) {
487:                    int ch = peekChar();
488:                    // Look for a single-char work delimiter:
489:                    if (ch == '=' || ch == '>' || ch == '"' || ch == '\''
490:                            || ch == '/') {
491:                        return true;
492:                    }
493:                    // Look for an end-of-comment or end-of-tag:                
494:                    if (ch == '-') {
495:                        Mark mark = mark();
496:                        if (((ch = nextChar()) == '>')
497:                                || ((ch == '-') && (nextChar() == '>'))) {
498:                            reset(mark);
499:                            return true;
500:                        } else {
501:                            reset(mark);
502:                            return false;
503:                        }
504:                    }
505:                    return false;
506:                } else {
507:                    return true;
508:                }
509:            }
510:
511:            /**
512:             * Register a new source file.
513:             * This method is used to implement file inclusion. Each included file
514:             * gets a unique identifier (which is the index in the array of source
515:             * files).
516:             *
517:             * @return The index of the now registered file.
518:             */
519:            private int registerSourceFile(final String file) {
520:                if (sourceFiles.contains(file)) {
521:                    return -1;
522:                }
523:
524:                sourceFiles.add(file);
525:                this .size++;
526:
527:                return sourceFiles.size() - 1;
528:            }
529:
530:            /**
531:             * Unregister the source file.
532:             * This method is used to implement file inclusion. Each included file
533:             * gets a uniq identifier (which is the index in the array of source
534:             * files).
535:             *
536:             * @return The index of the now registered file.
537:             */
538:            private int unregisterSourceFile(final String file) {
539:                if (!sourceFiles.contains(file)) {
540:                    return -1;
541:                }
542:
543:                sourceFiles.remove(file);
544:                this .size--;
545:                return sourceFiles.size() - 1;
546:            }
547:
548:            /**
549:             * Push a file (and its associated Stream) on the file stack.  THe
550:             * current position in the current file is remembered.
551:             */
552:            private void pushFile(String file, String encoding,
553:                    InputStreamReader reader) throws JasperException,
554:                    FileNotFoundException {
555:
556:                // Register the file
557:                String longName = file;
558:
559:                int fileid = registerSourceFile(longName);
560:
561:                if (fileid == -1) {
562:                    // Bugzilla 37407: http://issues.apache.org/bugzilla/show_bug.cgi?id=37407
563:                    if (reader != null) {
564:                        try {
565:                            reader.close();
566:                        } catch (Exception any) {
567:                            if (log.isDebugEnabled()) {
568:                                log.debug("Exception closing reader: ", any);
569:                            }
570:                        }
571:                    }
572:
573:                    err.jspError("jsp.error.file.already.registered", file);
574:                }
575:
576:                currFileId = fileid;
577:
578:                try {
579:                    CharArrayWriter caw = new CharArrayWriter();
580:                    char buf[] = new char[1024];
581:                    for (int i = 0; (i = reader.read(buf)) != -1;)
582:                        caw.write(buf, 0, i);
583:                    caw.close();
584:                    if (current == null) {
585:                        current = new Mark(this , caw.toCharArray(), fileid,
586:                                getFile(fileid), master, encoding);
587:                    } else {
588:                        current.pushStream(caw.toCharArray(), fileid,
589:                                getFile(fileid), longName, encoding);
590:                    }
591:                } catch (Throwable ex) {
592:                    log.error("Exception parsing file ", ex);
593:                    // Pop state being constructed:
594:                    popFile();
595:                    err.jspError("jsp.error.file.cannot.read", file);
596:                } finally {
597:                    if (reader != null) {
598:                        try {
599:                            reader.close();
600:                        } catch (Exception any) {
601:                            if (log.isDebugEnabled()) {
602:                                log.debug("Exception closing reader: ", any);
603:                            }
604:                        }
605:                    }
606:                }
607:            }
608:
609:            /**
610:             * Pop a file from the file stack.  The field "current" is retored
611:             * to the value to point to the previous files, if any, and is set
612:             * to null otherwise.
613:             * @return true is there is a previous file on the stack.
614:             *         false otherwise.
615:             */
616:            private boolean popFile() throws JasperException {
617:
618:                // Is stack created ? (will happen if the Jsp file we're looking at is
619:                // missing.
620:                if (current == null || currFileId < 0) {
621:                    return false;
622:                }
623:
624:                // Restore parser state:
625:                String fName = getFile(currFileId);
626:                currFileId = unregisterSourceFile(fName);
627:                if (currFileId < -1) {
628:                    err.jspError("jsp.error.file.not.registered", fName);
629:                }
630:
631:                Mark previous = current.popStream();
632:                if (previous != null) {
633:                    master = current.baseDir;
634:                    current = previous;
635:                    return true;
636:                }
637:                // Note that although the current file is undefined here, "current"
638:                // is not set to null just for convience, for it maybe used to
639:                // set the current (undefined) position.
640:                return false;
641:            }
642:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.