KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jcorporate > expresso > ext > controller > ServeTextFile


1 /* ====================================================================
2  * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
3  *
4  * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  *
18  * 3. The end-user documentation included with the redistribution,
19  * if any, must include the following acknowledgment:
20  * "This product includes software developed by Jcorporate Ltd.
21  * (http://www.jcorporate.com/)."
22  * Alternately, this acknowledgment may appear in the software itself,
23  * if and wherever such third-party acknowledgments normally appear.
24  *
25  * 4. "Jcorporate" and product names such as "Expresso" must
26  * not be used to endorse or promote products derived from this
27  * software without prior written permission. For written permission,
28  * please contact info@jcorporate.com.
29  *
30  * 5. Products derived from this software may not be called "Expresso",
31  * or other Jcorporate product names; nor may "Expresso" or other
32  * Jcorporate product names appear in their name, without prior
33  * written permission of Jcorporate Ltd.
34  *
35  * 6. No product derived from this software may compete in the same
36  * market space, i.e. framework, without prior written permission
37  * of Jcorporate Ltd. For written permission, please contact
38  * partners@jcorporate.com.
39  *
40  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
41  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
42  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
43  * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
44  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
46  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
47  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
48  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
49  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
50  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  * ====================================================================
53  *
54  * This software consists of voluntary contributions made by many
55  * individuals on behalf of the Jcorporate Ltd. Contributions back
56  * to the project(s) are encouraged when you make modifications.
57  * Please send them to support@jcorporate.com. For more information
58  * on Jcorporate Ltd. and its products, please see
59  * <http://www.jcorporate.com/>.
60  *
61  * Portions of this software are based upon other open source
62  * products and are subject to their respective licenses.
63  */

64
65 package com.jcorporate.expresso.ext.controller;
66
67 import com.jcorporate.expresso.core.controller.ControllerException;
68 import com.jcorporate.expresso.core.controller.ControllerRequest;
69 import com.jcorporate.expresso.core.controller.ControllerResponse;
70 import com.jcorporate.expresso.core.controller.DBController;
71 import com.jcorporate.expresso.core.controller.ServletControllerRequest;
72 import com.jcorporate.expresso.core.controller.State;
73 import com.jcorporate.expresso.core.misc.ConfigManager;
74 import com.jcorporate.expresso.core.security.filters.Filter;
75 import org.apache.log4j.Logger;
76
77 import javax.servlet.Servlet JavaDoc;
78 import javax.servlet.http.HttpServletRequest JavaDoc;
79 import javax.servlet.http.HttpServletResponse JavaDoc;
80 import javax.servlet.http.HttpSession JavaDoc;
81 import java.io.BufferedInputStream JavaDoc;
82 import java.io.ByteArrayOutputStream JavaDoc;
83 import java.io.File JavaDoc;
84 import java.io.FileInputStream JavaDoc;
85 import java.io.FileNotFoundException JavaDoc;
86 import java.io.IOException JavaDoc;
87 import java.io.OutputStream JavaDoc;
88 import java.io.PrintStream JavaDoc;
89 import java.io.PushbackInputStream JavaDoc;
90 import java.util.Date JavaDoc;
91 import java.util.Hashtable JavaDoc;
92 import java.util.Vector JavaDoc;
93
94 /**
95  * This controller is used to serve up text files. It helps provide a particularly
96  * useful mechanism for tutorial purposes.
97  * <p><b>PLEASE NOTE!</b>: It is DEFINITELY not recommended that this controller
98  * should be opened up to anybody but the Administrator in a production
99  * environment! It could be used by malicious attackers to cause the system
100  * to cough up password files, and many other things that they would not normally
101  * have access to </p>
102  *
103  * @author Michael Rimov - Adapted from code created by Peter Pilgrim.
104  */

105
106 public class ServeTextFile extends DBController {
107
108     /**
109      * List of locations to search for this file
110      */

111     static private Vector JavaDoc rootDirList = new Vector JavaDoc();
112
113     /**
114      * Our Log4J logger. See <a HREF="http://jakarta.apache.org/log4j/">The Log4j Website</a>
115      * for more information.
116      */

117     transient static private Logger log = Logger.getLogger("expresso.ext.controller.ServeTextFile");
118
119     /**
120      * A filter that efficiently removes (hopefully) all URL trickery that could
121      * result in unnecessary security problems
122      */

123     transient private static Filter fileNameFilter = null;
124
125
126     /**
127      * A filter that efficiently goes through a string and color codes the
128      * appropriate stuff for nice eye candy
129      */

130     transient private static Filter javaCodeFilter = null;
131
132
133     //--------------------------------------------------------------
134
//Here we have contstants for color coding java files
135
//--------------------------------------------------------------
136
public final static String JavaDoc DEFAULT_RESERVED_KEYWORD_COLOR = "#9900CC";
137     public final static String JavaDoc DEFAULT_PRIMITIVE_VAR_COLOR = "#008000";
138     public final static String JavaDoc DEFAULT_SPECIAL_KEYWORD_COLOR = "#4682B4"; // Light Blue
139
public final static String JavaDoc DEFAULT_SINGLE_QUOTE_COLOR = "#0066FF";
140     public final static String JavaDoc DEFAULT_DOUBLE_QUOTE_COLOR = "#0000CC";
141     public final static String JavaDoc DEFAULT_CSTYLE_COMMENT_COLOR = "#CC0033";
142     public final static String JavaDoc DEFAULT_CPLUS_COMMENT_COLOR = "B22222"; // firebrick
143
public final static String JavaDoc DEFAULT_DECIMAL_NUMBER_COLOR = "#996600";
144     protected final static String JavaDoc reservedKeywordColor = DEFAULT_RESERVED_KEYWORD_COLOR;
145     protected final static String JavaDoc primitiveVarColor = DEFAULT_PRIMITIVE_VAR_COLOR;
146     protected final static String JavaDoc specialKeywordColor = DEFAULT_SPECIAL_KEYWORD_COLOR;
147     protected final static String JavaDoc singleQuoteColor = DEFAULT_SINGLE_QUOTE_COLOR;
148     protected final static String JavaDoc doubleQuoteColor = DEFAULT_DOUBLE_QUOTE_COLOR;
149     protected final static String JavaDoc cstyleCommentColor = DEFAULT_CSTYLE_COMMENT_COLOR;
150     protected final static String JavaDoc cplusCommentColor = DEFAULT_CPLUS_COMMENT_COLOR;
151     protected final static String JavaDoc decimalNumberColor = DEFAULT_DECIMAL_NUMBER_COLOR;
152
153     /**
154      * Class used a structure to pass info around calls
155      */

156     class Parameters {
157         HttpServletRequest JavaDoc req; // Request
158
HttpServletResponse JavaDoc res; // Response
159
HttpSession JavaDoc session; // Session
160
String JavaDoc inputFilename; // Input Filename
161
String JavaDoc filename; // Resolved Filename
162
PrintStream JavaDoc out; // Output
163
}
164
165     /**
166      * A simple structure class to map a Java
167      * reserved keyword to a HTML colour code
168      */

169     static class ReservedWord {
170         String JavaDoc keyword;
171         String JavaDoc htmlcolor;
172
173         ReservedWord(String JavaDoc keyword, String JavaDoc htmlcolor) {
174             this.keyword = keyword;
175             this.htmlcolor = htmlcolor;
176         }
177     }
178
179     static protected final ServeTextFile.ReservedWord[] java_reserved_keywords = {
180         new ReservedWord("class", DEFAULT_RESERVED_KEYWORD_COLOR),
181         new ReservedWord("interface", DEFAULT_RESERVED_KEYWORD_COLOR),
182         new ReservedWord("extends", DEFAULT_RESERVED_KEYWORD_COLOR),
183         new ReservedWord("implements", DEFAULT_RESERVED_KEYWORD_COLOR),
184         new ReservedWord("goto", DEFAULT_RESERVED_KEYWORD_COLOR),
185         new ReservedWord("for", DEFAULT_RESERVED_KEYWORD_COLOR),
186         new ReservedWord("return", DEFAULT_RESERVED_KEYWORD_COLOR),
187         new ReservedWord("if", DEFAULT_RESERVED_KEYWORD_COLOR),
188         new ReservedWord("then", DEFAULT_RESERVED_KEYWORD_COLOR),
189         new ReservedWord("else", DEFAULT_RESERVED_KEYWORD_COLOR),
190         new ReservedWord("while", DEFAULT_RESERVED_KEYWORD_COLOR),
191         new ReservedWord("do", DEFAULT_RESERVED_KEYWORD_COLOR),
192         new ReservedWord("switch", DEFAULT_RESERVED_KEYWORD_COLOR),
193         new ReservedWord("case", DEFAULT_RESERVED_KEYWORD_COLOR),
194         new ReservedWord("default", DEFAULT_RESERVED_KEYWORD_COLOR),
195         new ReservedWord("instanceof", DEFAULT_RESERVED_KEYWORD_COLOR),
196         new ReservedWord("package", DEFAULT_RESERVED_KEYWORD_COLOR),
197         new ReservedWord("import", DEFAULT_RESERVED_KEYWORD_COLOR),
198         new ReservedWord("public", DEFAULT_RESERVED_KEYWORD_COLOR),
199         new ReservedWord("protected", DEFAULT_RESERVED_KEYWORD_COLOR),
200         new ReservedWord("private", DEFAULT_RESERVED_KEYWORD_COLOR),
201         new ReservedWord("super", DEFAULT_RESERVED_KEYWORD_COLOR),
202         new ReservedWord("new", DEFAULT_RESERVED_KEYWORD_COLOR),
203         new ReservedWord("this", DEFAULT_RESERVED_KEYWORD_COLOR),
204         new ReservedWord("try", DEFAULT_RESERVED_KEYWORD_COLOR),
205         new ReservedWord("catch", DEFAULT_RESERVED_KEYWORD_COLOR),
206         new ReservedWord("throw", DEFAULT_RESERVED_KEYWORD_COLOR),
207         new ReservedWord("throws", DEFAULT_RESERVED_KEYWORD_COLOR),
208         new ReservedWord("final", DEFAULT_RESERVED_KEYWORD_COLOR),
209         new ReservedWord("abstract", DEFAULT_RESERVED_KEYWORD_COLOR),
210         new ReservedWord("native", DEFAULT_RESERVED_KEYWORD_COLOR),
211         new ReservedWord("static", DEFAULT_RESERVED_KEYWORD_COLOR),
212         new ReservedWord("transient", DEFAULT_RESERVED_KEYWORD_COLOR),
213         new ReservedWord("void", DEFAULT_PRIMITIVE_VAR_COLOR),
214         new ReservedWord("boolean", DEFAULT_PRIMITIVE_VAR_COLOR),
215         new ReservedWord("char", DEFAULT_PRIMITIVE_VAR_COLOR),
216         new ReservedWord("int", DEFAULT_PRIMITIVE_VAR_COLOR),
217         new ReservedWord("short", DEFAULT_PRIMITIVE_VAR_COLOR),
218         new ReservedWord("long", DEFAULT_PRIMITIVE_VAR_COLOR),
219         new ReservedWord("float", DEFAULT_PRIMITIVE_VAR_COLOR),
220         new ReservedWord("double", DEFAULT_PRIMITIVE_VAR_COLOR),
221         new ReservedWord("null", DEFAULT_SPECIAL_KEYWORD_COLOR),
222         new ReservedWord("true", DEFAULT_SPECIAL_KEYWORD_COLOR),
223         new ReservedWord("false", DEFAULT_SPECIAL_KEYWORD_COLOR)
224     };
225
226     protected static Hashtable JavaDoc fast_keyword_map = null;
227
228     public ServeTextFile() {
229         State s = new State("serveTextFile", "Serve A Text File");
230         s.addRequiredParameter("filename");
231         this.addState(s);
232
233         s = new State("serveJavaFile", "Serve a Java File");
234         s.addRequiredParameter("filename");
235         this.addState(s);
236
237         String JavaDoc baseRootDir = ConfigManager.getWebAppDir() + "/WEB-INF/src";
238         rootDirList.add(baseRootDir);
239         baseRootDir = ConfigManager.getWebAppDir();
240         rootDirList.add(baseRootDir);
241
242         if (fileNameFilter == null) {
243             //We use this to filter out all URL trickery that we can think of
244
fileNameFilter = new Filter(new String JavaDoc[]{"|", "..", ">", "<"},
245                     new String JavaDoc[]{"", "", "", ""});
246         }
247
248         //
249
//Initialize the Java keyword map
250
//
251
if (fast_keyword_map == null) {
252             fast_keyword_map = new Hashtable JavaDoc(java_reserved_keywords.length);
253
254             for (int k = 0; k < java_reserved_keywords.length; ++k) {
255                 fast_keyword_map.put(java_reserved_keywords[k].keyword,
256                         java_reserved_keywords[k]);
257             }
258         }
259
260         this.setInitialState("serveJavaFile");
261         this.setSchema(com.jcorporate.expresso.core.ExpressoSchema.class);
262     }
263
264     /**
265      * Serves up a basic text file as specified by the parameter. Our goal
266      * here is to provide something that is reasonably secure in that we remove
267      * all URL trickery.
268      *
269      * @param request The <code>ControllerRequest</code> Object
270      * @param response The <code>ControllerResponse</code> Object
271      * @return ControllerResponse
272      * @throws ControllerException upon error
273      */

274     protected ControllerResponse runServeTextFileState(ControllerRequest request,
275                                                        ControllerResponse response) throws ControllerException {
276
277         ServletControllerRequest servRequest;
278         try {
279             servRequest = (ServletControllerRequest) request;
280         } catch (ClassCastException JavaDoc ex) {
281             throw new ControllerException("This controller must be run within only a http environment");
282         }
283
284
285         //
286
//ControllerRequest contains pointers to low level HttpServlet stuff
287
//if it can be downcast to ServletControllerRequest
288
//
289
HttpServletRequest JavaDoc req = (HttpServletRequest JavaDoc) servRequest.getServletRequest();
290         HttpServletResponse JavaDoc res = (HttpServletResponse JavaDoc) servRequest.getServletResponse();
291         Servlet JavaDoc servlet = servRequest.getCallingServlet();
292
293         String JavaDoc fileSep = System.getProperty("file.separator");
294         String JavaDoc inputFilename = req.getParameter("filename");
295
296         try {
297
298             // Append the input filename to the root directory
299
if (inputFilename == null) {
300                 throw new ControllerException("filename parameter is not set.");
301             }
302
303             //
304
//By running it throuhg the filter, we should be able to remove all
305
//sorts of URL trickery that occurs by people sending urls like a
306
//URL encoded version of:
307
//mail hacker@hotmail.com -s Password! < cat /../../../etc/passwd
308
//(And YES, this kind of attack happens often!)
309
//
310
inputFilename = fileNameFilter.stripFilter(inputFilename);
311
312             if (inputFilename.length() == 0) {
313                 throw new ControllerException("filename parameter is not set.");
314             }
315
316             if (!(inputFilename.endsWith(".java") ||
317                     inputFilename.endsWith(".cpp") ||
318                     inputFilename.endsWith(".cc") ||
319                     inputFilename.endsWith(".jpg") ||
320                     inputFilename.endsWith(".jpeg") ||
321                     inputFilename.endsWith(".png") ||
322                     inputFilename.endsWith(".jsp") ||
323                     inputFilename.endsWith(".txt") ||
324                     inputFilename.endsWith(".wm"))) {
325                 throw new ControllerException("Sorry, it is forbidden to serve this type of file.");
326             }
327
328             boolean fileWasServed = false;
329
330             for (int k = 0; k < rootDirList.size(); ++k) {
331                 String JavaDoc rootDir = (String JavaDoc) rootDirList.elementAt(k);
332                 File JavaDoc file = new File JavaDoc(rootDir, inputFilename);
333                 String JavaDoc filename = file.getPath();
334
335                 if (file.exists()) {
336                     if (!file.canRead()) {
337                         throw new IOException JavaDoc("not readable filename:`" +
338                                 inputFilename + "'");
339                     }
340                     if (file.isDirectory()) {
341                         throw new IOException JavaDoc("cannot serve a directory as filename:`" +
342                                 inputFilename + "'");
343                     }
344
345                     fileWasServed = true; /*!*/
346                     //
347
//Set this value to indicate we don't want to do a normal struts forward
348
//
349
response.setCustomResponse(true);
350
351                     // Get the MIME type to return the browser
352
String JavaDoc contentType = servlet.getServletConfig().getServletContext().getMimeType(filename);
353
354                     if (contentType == null) {
355                         contentType = "text/plain";
356                     }
357
358                     if (log.isInfoEnabled()) {
359                         log.info("BasicFileServeServlet: Serving file:`" + filename +
360                                 "' type:" + contentType);
361                     }
362
363                     // Create a buffer for the file contents
364
ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc(8192);
365
366                     // Extract the file contents
367
returnFile(filename, baos);
368
369                     // Provided no I/O exception occurred, pump the buffered
370
// data to the browser now.
371
OutputStream JavaDoc out = res.getOutputStream();
372                     res.setContentType(contentType);
373                     baos.writeTo(out);
374                     out.flush();
375                     out.close();
376                     break;
377                 }
378             }
379             if (!fileWasServed) {
380                 throw new FileNotFoundException JavaDoc("no such file: `" +
381                         inputFilename + "'");
382             }
383         } catch (FileNotFoundException JavaDoc ex) {
384             log.error("FileNotFoundException locating file file", ex);
385             throw new ControllerException("FileNotFoundException Error transferring file", ex);
386         } catch (java.io.IOException JavaDoc ioe) {
387             log.error("I/O Error transferring file", ioe);
388             throw new ControllerException("I/O Error transferring file", ioe);
389         }
390
391         return response;
392     }
393
394     protected void returnFile(String JavaDoc filename, OutputStream JavaDoc out)
395             throws FileNotFoundException JavaDoc, IOException JavaDoc {
396         FileInputStream JavaDoc fis = null;
397
398         try {
399             fis = new FileInputStream JavaDoc(filename);
400
401             byte[] buffer = new byte[8192];
402             int bytesRead;
403
404             while ((bytesRead = fis.read(buffer)) != -1) {
405                 out.write(buffer, 0, bytesRead);
406             }
407         } finally {
408             if (fis != null) {
409                 fis.close();
410             }
411         }
412     }
413
414     /**
415      * Serves up a java source file as specified by the parameter. This
416      * state is different from that of servTextFile in that it color codes
417      * all the keywords, etc in the java file.
418      * <p/>
419      * Our goal here is to provide something that is reasonably secure in that we remove
420      * all URL trickery, and we also only serve up NON source code files. Again,
421      * this should be NOT used in a production environment and only exists for
422      * teaching purposes.
423      *
424      * @param request The <code>ControllerRequest</code> Object
425      * @param response The <code>ControllerResponse</code> Object
426      * @return ControllerResponse
427      * @throws ControllerException upon error
428      */

429     protected ControllerResponse runServeJavaFileState(ControllerRequest request,
430                                                        ControllerResponse response) throws ControllerException {
431         ServletControllerRequest servRequest;
432         try {
433             servRequest = (ServletControllerRequest) request;
434         } catch (ClassCastException JavaDoc ex) {
435             throw new ControllerException("This controller must be run within only a http environment");
436         }
437
438
439         //
440
//ControllerRequest contains pointers to low level HttpServlet stuff
441
//if it can be downcast to ServletControllerRequest
442
//
443
HttpServletRequest JavaDoc req = (HttpServletRequest JavaDoc) servRequest.getServletRequest();
444         HttpSession JavaDoc session = req.getSession(true);
445         HttpServletResponse JavaDoc res = (HttpServletResponse JavaDoc) servRequest.getServletResponse();
446         Servlet JavaDoc servlet = servRequest.getCallingServlet();
447
448         String JavaDoc fileSep = System.getProperty("file.separator");
449         String JavaDoc inputFilename = req.getParameter("filename");
450
451         try {
452             // Append the input filename to the root directory
453
if (inputFilename == null) {
454                 throw new ControllerException("filename parameter is not set.");
455             }
456
457
458             // Append the input filename to the root directory
459
if (inputFilename == null) {
460                 throw new ControllerException("filename parameter is not set.");
461             }
462
463             //
464
//By running it throuhg the filter, we should be able to remove all
465
//sorts of URL trickery that occurs by people sending urls like a
466
//URL encoded version of:
467
//mail hacker@hotmail.com -s Password! < cat /../../../etc/passwd
468
//(And YES, this kind of attack happens often!)
469
//
470
inputFilename = fileNameFilter.stripFilter(inputFilename);
471
472             if (inputFilename.length() == 0) {
473                 throw new ControllerException("filename parameter is not set.");
474             }
475
476             if (!(inputFilename.endsWith(".java"))) {
477                 throw new ControllerException(
478                         "Sorry, it is forbidden to serve this type of file. This servlet only serves Java source files!");
479             }
480
481             boolean fileWasServed = false;
482
483             for (int k = 0; k < rootDirList.size(); ++k) {
484                 String JavaDoc rootDir = (String JavaDoc) rootDirList.elementAt(k);
485                 File JavaDoc file = new File JavaDoc(rootDir, inputFilename);
486                 String JavaDoc filename = file.getPath();
487
488                 if (file.exists()) {
489                     if (!file.canRead()) {
490                         throw new IOException JavaDoc("not readable filename:`" +
491                                 inputFilename + "'");
492                     }
493                     if (file.isDirectory()) {
494                         throw new IOException JavaDoc("cannot serve a directory as filename:`" +
495                                 inputFilename + "'");
496                     }
497
498                     fileWasServed = true; /*!*/
499
500                     //
501
//Set this value to indicate we don't want to do a normal struts forward
502
//
503
response.setCustomResponse(true);
504
505                     // Get the MIME type to return the browser
506
String JavaDoc contentType = "text/html";
507                     if (log.isInfoEnabled()) {
508                         log.info("JavaFileServeServlet: Serving file:`" + filename +
509                                 "' type:" + contentType);
510                     }
511
512                     // Create a buffer for the file contents
513
ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc(32678);
514                     PrintStream JavaDoc prs = new PrintStream JavaDoc(baos);
515
516                     // Set up parameter structure
517
Parameters params = new Parameters();
518                     params.req = req;
519                     params.res = res;
520                     params.session = session;
521                     params.inputFilename = inputFilename;
522                     params.filename = filename;
523                     params.out = prs;
524
525                     // Extract the file contents and format HTML
526
returnHTMLFormattedFile(params);
527                     prs.flush(); // MAKE SURE!!!
528

529                     // Provided no I/O exception occurred, pump the buffered
530
// data to the browser now.
531
OutputStream JavaDoc out = res.getOutputStream();
532                     res.setContentType(contentType);
533                     baos.writeTo(out);
534                     out.flush();
535                     out.close();
536                     break;
537                 }
538             }
539             if (!fileWasServed) {
540                 throw new FileNotFoundException JavaDoc("no such file: `" +
541                         inputFilename + "'");
542             }
543
544         } catch (FileNotFoundException JavaDoc ex) {
545             log.error("FileNotFoundException locating file file", ex);
546             throw new ControllerException("FileNotFoundException Error transferring file", ex);
547         } catch (java.io.IOException JavaDoc ioe) {
548             log.error("I/O Error transferring file", ioe);
549             throw new ControllerException("I/O Error transferring file", ioe);
550         }
551
552         return response;
553     }
554
555     public void returnHTMLFormattedFile(Parameters params)
556             throws FileNotFoundException JavaDoc, IOException JavaDoc {
557         writeHeader(params);
558         writeContent(params);
559         writeFooter(params);
560     }
561
562     public void writeHeader(Parameters params)
563             throws FileNotFoundException JavaDoc, IOException JavaDoc {
564         PrintStream JavaDoc out = params.out;
565         out.println("<html>");
566         out.println("<head>");
567         out.println("<title>Java Source File: `" + params.inputFilename +
568                 "'</title>");
569         out.println("<meta name=\"generator\" value=\"" +
570                 getClass().getName() + "\" >");
571         out.println("<meta name=\"published_date\" value=\"" + new Date JavaDoc() +
572                 "\" >");
573         out.println("</head>");
574         out.println("<body bgcolor=\"#FFFFFF\" >");
575
576         File JavaDoc file = new File JavaDoc(params.filename);
577         out.println("<p><font face=\"Lucida, Georgia, Arial,Helvetica\" size=\"-1\" color=\"#000000\" >filename: <b>" +
578                 params.inputFilename + "</b><br>");
579         out.println("file size: <b>" + file.length() + "</b><br>");
580         out.println("last modified: <b>" + new Date JavaDoc(file.lastModified()) +
581                 "</b><br>");
582         out.println("</font></p>");
583     }
584
585     protected void writeFooter(Parameters params)
586             throws FileNotFoundException JavaDoc, IOException JavaDoc {
587         PrintStream JavaDoc out = params.out;
588         out.println("</body>");
589         out.println("</html>");
590     }
591
592     protected void writeContent(Parameters params)
593             throws FileNotFoundException JavaDoc, IOException JavaDoc {
594         PrintStream JavaDoc out = params.out;
595         FileInputStream JavaDoc fis = null;
596         BufferedInputStream JavaDoc bis = null;
597         PushbackInputStream JavaDoc pis = null;
598         boolean insideDQuote = false;
599         boolean insideSQuote = false;
600         boolean cstyleComment = false;
601
602         try {
603
604             // Try to open a file stream to the Java source file
605
fis = new FileInputStream JavaDoc(params.filename);
606             bis = new BufferedInputStream JavaDoc(fis, 8192);
607             pis = new PushbackInputStream JavaDoc(bis, 256);
608
609             // Write start of the content section
610
out.println("<pre>");
611             out.println("<font face=\"Courier New, Monospace, Helvetica, San-serif\" size=\"+0\" color=\"#000000\" >");
612
613             int c1 = pis.read();
614
615             while (c1 >= 0) {
616
617                 // Pipe through any blank spaces
618
while (Character.isWhitespace((char) c1)) {
619                     out.print((char) c1);
620                     c1 = pis.read();
621                 }
622                 if (c1 < 0) {
623
624                     // EOF - End of file reached
625
break;
626                 }
627
628                 if (log.isDebugEnabled()) {
629                     System.out.print((char) c1);
630                 }
631
632                 if (c1 == '/') {
633                     int c2 = pis.read();
634
635                     if (c2 == '/') {
636
637                         // Directly hand 'C++' style comment
638
out.print("<font color=\"" + cplusCommentColor +
639                                 "\">//");
640
641                         if (log.isDebugEnabled()) {
642                             System.out.println("C++ comment");
643                         }
644
645                         c2 = pis.read();
646
647                         while (c2 != -1 && c2 != '\n') {
648                             out.print(substituteEntity((char) c2));
649                             c2 = pis.read();
650                         }
651
652                         out.print("</font>\n");
653                         c1 = pis.read(); // READ NEXT
654
continue;
655                     } else if (c2 == '*') {
656
657                         // Start of 'C' style comment
658
if (log.isDebugEnabled()) {
659                             System.out.println("C comment start");
660                         }
661                         cstyleComment = true;
662                         out.print("<font color=\"" + cstyleCommentColor +
663                                 "\">/*");
664                         c1 = pis.read(); // READ NEXT
665
continue;
666                     } else {
667                         pis.unread(c2);
668                     }
669                 } else if (c1 == '*') {
670                     int c2 = pis.read();
671
672                     if (c2 == '/') {
673
674                         // End of 'C' style comment
675
if (log.isDebugEnabled()) {
676                             System.out.println("C comment end"); // FIXME:
677
}
678
679                         cstyleComment = false;
680                         out.print("*/</font>");
681                         c1 = pis.read(); // READ NEXT
682
continue;
683                     } else {
684                         pis.unread(c2);
685                     }
686                 }
687                 if (c1 == '\"' && !cstyleComment) {
688                     if (!insideDQuote) {
689                         out.print("<font color=\"" + doubleQuoteColor +
690                                 "\">&quot;");
691                     } else {
692                         out.print("&quot;</font>");
693                     }
694
695                     insideDQuote = !insideDQuote;
696                     if (log.isDebugEnabled()) {
697                         System.out.println("double quotes:" + insideDQuote);
698                     }
699                 } else if (c1 == '\'' && !cstyleComment && !insideDQuote) {
700                     if (!insideSQuote) {
701                         out.print("<font color=\"" + singleQuoteColor +
702                                 "\">&#039;");
703                     } else {
704                         out.print("&#039;</font>");
705                     }
706
707                     insideSQuote = !insideSQuote;
708                     if (log.isDebugEnabled()) {
709                         System.out.println("single quotes:" + insideSQuote);
710                     }
711                 } else if (Character.isDigit((char) c1) && !cstyleComment &&
712                         !insideSQuote && !insideDQuote) {
713
714                     // Handle parsing of decimal or floating
715
// formatting numbers here
716
boolean valid = true;
717                     StringBuffer JavaDoc tokenBuffer = new StringBuffer JavaDoc();
718                     tokenBuffer.append((char) c1);
719
720                     int c2 = pis.read();
721
722                     while (Character.isDigit((char) c2)) {
723                         tokenBuffer.append((char) c2);
724                         c2 = pis.read();
725                     }
726
727                     pis.mark(256);
728                     if (log.isDebugEnabled()) {
729                         System.out.println("(1) token=`" + tokenBuffer.toString() +
730                                 "' (c2:" + c2 + "<" + (char) c2 + ")");
731                     }
732
733                     if (c2 == '.') {
734                         tokenBuffer.append((char) c2);
735                         c2 = pis.read();
736                         if (log.isDebugEnabled()) {
737                             System.out.println("(2) token=`" +
738                                     tokenBuffer.toString() + "' (c2:" + c2 +
739                                     "<" + (char) c2 + ")");
740                         }
741
742                         if (c2 == 'e' || c2 == 'E') {
743                             tokenBuffer.append((char) c2);
744                             c2 = pis.read();
745                             if (log.isDebugEnabled()) {
746                                 System.out.println("(3) token=`" +
747                                         tokenBuffer.toString() +
748                                         "' (c2:" + c2 + "<" + (char) c2 +
749                                         ")");
750                             }
751                         }
752
753                         System.out.println("(4) token=`" +
754                                 tokenBuffer.toString() + "' (c2:" + c2 +
755                                 "<" + (char) c2 + ")");
756
757                         if (c2 == '+' || c2 == '-') {
758                             tokenBuffer.append((char) c2);
759                             c2 = pis.read();
760                         }
761                         if (Character.isDigit((char) c2)) {
762                             while (Character.isDigit((char) c2)) {
763                                 tokenBuffer.append((char) c2);
764                                 c2 = pis.read();
765                             }
766                         } else {
767
768                             // Sorry, not a valid floating point number
769
// `[0-9]+\.(E|e)?(+|-)?[0-9]+'
770
valid = false;
771                             pis.reset();
772                         }
773                     }
774
775                     pis.unread(c2); // Pushback the last unread!
776

777                     if (valid) {
778                         out.print("<font color=\"" + decimalNumberColor +
779                                 "\" >");
780                     }
781
782                     out.print(tokenBuffer.toString());
783
784                     if (valid) {
785                         out.print("</font>");
786                     }
787                 } else if (Character.isLetter((char) c1) && !cstyleComment &&
788                         !insideSQuote && !insideDQuote) {
789
790                     // Handle reserved keywords here
791
StringBuffer JavaDoc tokenBuffer = new StringBuffer JavaDoc();
792                     tokenBuffer.append((char) c1);
793
794                     int c2 = pis.read();
795
796                     while (Character.isLetter((char) c2)) {
797                         tokenBuffer.append((char) c2);
798                         c2 = pis.read();
799                     }
800
801                     pis.unread(c2); // Pushback the last unread!
802

803                     // Does the token match a reserved Java keyword?
804
boolean wasMatched = false;
805                     String JavaDoc token = tokenBuffer.toString();
806                     if (log.isDebugEnabled()) {
807                         System.out.println("<" + token + ">(" + c2 + "/`" +
808                                 (char) c2 + "')");
809                     }
810
811                     ReservedWord reservedWord = (ReservedWord) fast_keyword_map.get(token);
812
813                     if (reservedWord != null) {
814
815                         // Matched a reserved Java keyword
816
wasMatched = true;
817                     }
818                     if (wasMatched) {
819                         out.print("<font color=\"" + reservedWord.htmlcolor +
820                                 "\" >");
821                     }
822
823                     out.print(token);
824
825                     if (wasMatched) {
826                         out.print("</font>");
827                     }
828                 } else {
829                     out.print(substituteEntity((char) c1));
830                 }
831
832                 // DON'T FORGET: Read the next character from the pushback stream!
833
c1 = pis.read();
834             }
835
836             // Write end of the content section
837
out.println("</font>");
838             out.println("</pre>");
839         } finally {
840             if (pis != null) {
841                 pis.close();
842             }
843             if (fis != null) {
844                 fis.close();
845             }
846         }
847     }
848
849     protected static final String JavaDoc substituteEntity(char c9) {
850         switch (c9) {
851             case '<':
852                 return "&lt;";
853
854             case '>':
855                 return "&gt;";
856
857             case '&':
858                 return "&amp;";
859
860             case '\"':
861                 return "&quot;";
862         }
863
864         return new String JavaDoc(new char[]{c9});
865     }
866
867     public String JavaDoc getTitle() {
868         return "Serve Text File";
869     }
870
871
872 }
Popular Tags