KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > servlet > servlets > JarServerServlet


1
2 /*
3  * Enhydra Java Application Server Project
4  *
5  * The contents of this file are subject to the Enhydra Public License
6  * Version 1.1 (the "License"); you may not use this file except in
7  * compliance with the License. You may obtain a copy of the License on
8  * the Enhydra web site ( http://www.enhydra.org/ ).
9  *
10  * Software distributed under the License is distributed on an "AS IS"
11  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
12  * the License for the specific terms governing rights and limitations
13  * under the License.
14  *
15  * The Initial Developer of the Enhydra Application Server is Lutris
16  * Technologies, Inc. The Enhydra Application Server and portions created
17  * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
18  * All Rights Reserved.
19  *
20  * Contributor(s):
21  *
22  * $Id: JarServerServlet.java,v 1.7 2005/03/24 10:51:25 slobodan Exp $
23  */

24
25 package org.enhydra.servlet.servlets;
26
27 import java.io.IOException JavaDoc;
28 import java.io.InputStream JavaDoc;
29 import java.io.OutputStream JavaDoc;
30 import java.util.StringTokenizer JavaDoc;
31 import java.util.zip.ZipEntry JavaDoc;
32 import java.util.zip.ZipFile JavaDoc;
33
34 import javax.servlet.ServletConfig JavaDoc;
35 import javax.servlet.ServletContext JavaDoc;
36 import javax.servlet.ServletException JavaDoc;
37 import javax.servlet.ServletOutputStream JavaDoc;
38 import javax.servlet.http.HttpServlet JavaDoc;
39 import javax.servlet.http.HttpServletRequest JavaDoc;
40 import javax.servlet.http.HttpServletResponse JavaDoc;
41
42 import com.lutris.http.MimeType;
43 import com.lutris.logging.LogChannel;
44 import com.lutris.logging.Logger;
45 import com.lutris.logging.StandardLogger;
46 //SV import org.enhydra.servlet.connectionMethods.http.*;
47
//SV import org.enhydra.servlet.servletManager.EnhydraServletContext;
48

49
50 /**
51  * This class serves files from jar/zip files for HTTP requests.
52  * Currently only a
53  * limited Http GET request will be processed. CGI arguments will
54  * not be processed. The initArg "jarFile" sets the name of the jar
55  * or zip file to serve files from.
56  *
57  * @version $Revision: 1.7 $
58  * @auther Mark Sanguinetti
59  * @auther Shawn McMurdo
60  */

61 public class JarServerServlet extends HttpServlet JavaDoc {
62
63     /**
64      * Buffer size for writing one stream to another.
65      */

66     private static final int buffer_size = 1024*1;
67
68     /**
69      * Html text to send client for a file not found.
70      */

71     private final static String JavaDoc NOT_FOUND_MSG =
72         "<TITLE>Not Found</TITLE><H1>Not Found</H1> " +
73         "The requested object does not exist on this Enhydra Server. " +
74         "The link you followed is either outdated, inaccurate, " +
75         "or the server has been instructed not to let you have it.";
76
77     /**
78      * Html text to send client when Access to file denied.
79      */

80     private final static String JavaDoc ACCESS_DENIED_MSG =
81         "<TITLE>Access Denied</TITLE><H1>Access Denied</H1> " +
82         "Access is not allowed to the requested file. ";
83
84     /**
85      *
86      */

87     private final static String JavaDoc SC_MOVED_PERMANENTLY_MSG =
88         "<TITLE>Moved Permanently</TITLE><H1>Moved Permanently</H1> " +
89         "Resource has been moved";
90
91     /**
92      * The logging channel.
93      */

94     private LogChannel logChannel;
95     
96     /*
97      * If we create the central logger, we save a copy of it for later
98      * initialization. If we didn't create it, this will be null.
99      */

100     private StandardLogger standardLogger;
101     
102     /*
103      * If we create the central logger, we will need to initialize it later
104      * when init() is called.
105      */

106     private boolean needToConfigureLogChannel = false;
107     
108     /**
109      * The Servlet context.
110      */

111     private ServletContext JavaDoc myContext;
112
113     /**
114      * The jar file for the file server. It is
115      * specified in the servlet initArgs.
116      */

117     private String JavaDoc jarFileName = null;
118     private ZipFile JavaDoc jarFile = null;
119     /**
120      * The default inner file for the file server. It is
121      * specified in the servlet initArgs.
122      */

123     private String JavaDoc defaultInner = null;
124
125     /**
126      * Number of files served by this servlet.
127      */

128     private long numServed = 0;
129
130     /**
131      * Class for determining the mime type of a file
132      */

133     private MimeType mimetypes = new MimeType();
134     
135     //SV enabling relative referencing to jar file
136
/**
137      * The document root for the jar server
138      * specified in servlet context.
139      */

140     private Path docRoot = null;
141     
142     /**
143      * Create a new JarServerServlet.
144      */

145     public JarServerServlet() {
146         super();
147         if (Logger.getCentralLogger() == null) {
148             standardLogger = new StandardLogger(true);
149             needToConfigureLogChannel = true;
150         }
151         logChannel = Logger.getCentralLogger().getChannel("Enhydra");
152     }
153
154     /**
155      * This initializes the servlet and gets the jarFile parameter.
156      *
157      * @param config The servlet configuration object.
158      * @exception If an exception occured during initialztion
159      */

160     public void init(ServletConfig JavaDoc config)
161         throws ServletException JavaDoc {
162         super.init(config);
163         myContext = config.getServletContext();
164
165         jarFileName = config.getInitParameter("jarFile");
166         defaultInner = config.getInitParameter("default");
167         
168         //SV adition with pourpose to enable locating jar file
169
// relatively to DocRoot
170
String JavaDoc docRoot = myContext.getRealPath("");
171         
172         // covert to internal represenation of a path ('/' format)
173
String JavaDoc tmp = docRoot.replace('\\', '/');
174         if (!tmp.startsWith("/")) {
175             tmp = "/" + tmp;
176         }
177         if (!tmp.endsWith("/")) {
178             tmp = tmp + "/";
179         }
180
181         // parse out info in path and create a cleaned up
182
// url path
183
StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
184         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(tmp, "/");
185         sb.append("/");
186         while (st.hasMoreTokens()) {
187             String JavaDoc tok = st.nextToken();
188             if (st.countTokens() > 0) {
189                 sb.append(tok);
190                 sb.append("/");
191             } else if (st.countTokens() == 0) {
192                 sb.append(tok);
193             } else {
194                 // should never happen
195
System.err.println("ERROR: no able to determine DocRoot");
196             }
197         }
198         docRoot = sb.toString();
199         try {
200             jarFile = new ZipFile JavaDoc(jarFileName);
201         } catch (IOException JavaDoc ioe) {
202             try {
203                 jarFileName = docRoot+"/"+jarFileName;
204                 jarFile = new ZipFile JavaDoc(jarFileName);
205             } catch (IOException JavaDoc ioex) {
206                 throw new ServletException JavaDoc(ioe.getMessage());
207             }
208         }
209
210         //Try to get the logging channel, if we are being run under
211
// the MultiServer.
212
//SV if (myContext instanceof EnhydraServletContext) {
213
//SV EnhydraServletContext lbsContext =
214
//SV (EnhydraServletContext) myContext;
215
//SV logChannel = lbsContext.getLogChannel();
216
//SV }
217
logInfo("Starting Jar Server Servlet with jarFile " + jarFileName);
218     }
219
220     /**
221      * This method will process a limited http GET request for a file.
222      * The method will serve files, but will not process cgi arguments.
223      *
224      * @param req encapsulates the request to the servlet.
225      * @param res encapsulates the response from the servlet.
226      * @exception if the request could not be handled.
227      * @exception if detected when processing.
228      */

229     public void doGet(HttpServletRequest JavaDoc req, HttpServletResponse JavaDoc res)
230         throws ServletException JavaDoc, IOException JavaDoc {
231         
232         String JavaDoc pathInfo = req.getPathInfo();
233                 
234         /*SV bug fix for null option
235         * if no iner file specified sevlet will present default one
236         */

237         if (pathInfo==null || pathInfo.equals("") || pathInfo.equals("/")) {
238             pathInfo = defaultInner;
239         }
240         
241         /*SV bug fix
242         * path starting with '/' is not authorized
243         * ZipEntry would not be created in that case
244         */

245         if (pathInfo.startsWith("/")) {
246             pathInfo = pathInfo.substring(1);
247         }
248
249         ZipEntry JavaDoc jarEntry = jarFile.getEntry(pathInfo);
250         if (isAuth(pathInfo)) {
251                   processFileRequest(jarEntry, req, res);
252               } else {
253                   // path containing '..' is not authorized
254
res.sendError(res.SC_NOT_FOUND, NOT_FOUND_MSG);
255                   logInfo("JarServerServlet: File " + pathInfo + " not Found.");
256               }
257     }
258
259     /**
260      *
261      */

262     private void processFileRequest(ZipEntry JavaDoc file, HttpServletRequest JavaDoc req,
263         HttpServletResponse JavaDoc res) throws IOException JavaDoc {
264
265         if (file != null) {
266             // file exists
267
if (file.isDirectory()) {
268                 // don't do directories
269
res.sendError(res.SC_NOT_FOUND, NOT_FOUND_MSG);
270                 logInfo("JarServerServlet: File " + file + " not Found.");
271             } else {
272                 // send requested file
273
sendPage(file, res);
274             }
275         } else {
276             // file doesn't exist
277
res.sendError(res.SC_NOT_FOUND, NOT_FOUND_MSG);
278             logInfo("JarServerServlet: File " + file + " not Found.");
279         }
280      }
281
282     /**
283      * Test if path is authorized. A path is authorized if
284      * it does not contain a '..'. The browser should resolve
285      * the '..'.
286      *
287      * @param path requested path
288      * @return true if path is authorized
289      */

290     private boolean isAuth(String JavaDoc path) {
291
292         if (path.indexOf("..") == -1) {
293             return true;
294         }
295         return false;
296     }
297
298     /**
299      *
300      *
301      */

302     private void sendPage(ZipEntry JavaDoc file, HttpServletResponse JavaDoc res)
303             throws IOException JavaDoc {
304
305         String JavaDoc filetype = mimetypes.getType(file.getName());
306         res.setContentType(filetype);
307         Long JavaDoc len = new Long JavaDoc(file.getSize());
308         res.setHeader("Content-Length", len.toString());
309         ServletOutputStream JavaDoc out = res.getOutputStream();
310         InputStream JavaDoc in = jarFile.getInputStream(file);
311         writeFile(out, in);
312         in.close();
313         numServed++;
314     }
315
316     /**
317      * Http POST command is currently not supported and indicates
318      * this sending a message to the client.
319      *
320      * @param req encapsulates the request to the servlet.
321      * @param res encapsulates the response from the servlet.
322      * @exception if the request could not be handled.
323      * @exception if detected when processing.
324      */

325     public void doPost (HttpServletRequest JavaDoc req, HttpServletResponse JavaDoc res)
326         throws ServletException JavaDoc, IOException JavaDoc {
327         res.sendError(res.SC_NOT_IMPLEMENTED);
328         logInfo("JarServerServlet: Access Denied.");
329     }
330
331     /**
332      * Returns a string containing servlet information including name,
333      * and jarFile.
334      *
335      * @return Servlet information.
336      */

337     public String JavaDoc getServletInfo() {
338         return "A JarServerServlet, with jar file " + jarFileName;
339     }
340
341     /**
342      * Extra status info, shown by the Enhydra Server admin status page.
343      */

344     public String JavaDoc toHtml() {
345         return "Serving files from the jar " + jarFileName + ".<BR>\n" +
346                numServed + " files served.";
347     }
348
349     /**
350      * Transfers from one stream to another via a buffer. In this case
351      * the input stream is a file to be transferred and the output
352      * stream is servlet output stream.
353      *
354      * @param out The destination stream.
355      * @param in The source stream.
356      * @exception if an error occured during IO operations.
357      */

358     private void writeFile(OutputStream JavaDoc out, InputStream JavaDoc in)
359             throws IOException JavaDoc {
360
361         byte buffer[] = new byte[buffer_size];
362         while (true) {
363             int n = in.read(buffer);
364             if (n == -1) break;
365             out.write(buffer, 0, n);
366         }
367     }
368
369     /**
370      * Write standard (non error) information to the log. If logChannel
371      * is not null then the information will be logged to the server
372      * log channel otherwise the information
373      * will be logged to the standard servlet log.
374      *
375      * @param msg The message to be logged.
376      */

377     private void logInfo(String JavaDoc msg) {
378         if (logChannel != null) {
379               logChannel.write(Logger.INFO, msg);
380         } else {
381             myContext.log(msg);
382           }
383     }
384
385     /**
386      * Write error information to the log. If logChannel is not null
387      * then the information will be logged to the server log channel
388      * otherwise the information will be logged to
389      * the standard servlet log.
390      *
391      * @param err The error message to be logged.
392      * @param e The exception to be logged.
393      */

394     private void logError(String JavaDoc err, Exception JavaDoc e) {
395           if (logChannel != null) {
396               logChannel.write(Logger.ERROR, err, e);
397         } else {
398             myContext.log(e, err);
399         }
400     }
401 }
402
403
Popular Tags