001: package com.quadcap.http.servlets.file;
002:
003: /* Copyright 1998 - 2003 Quadcap Software. All rights reserved.
004: *
005: * This software is distributed under the Quadcap Free Software License.
006: * This software may be used or modified for any purpose, personal or
007: * commercial. Open Source redistributions are permitted. Commercial
008: * redistribution of larger works derived from, or works which bundle
009: * this software requires a "Commercial Redistribution License"; see
010: * http://www.quadcap.com/purchase.
011: *
012: * Redistributions qualify as "Open Source" under one of the following terms:
013: *
014: * Redistributions are made at no charge beyond the reasonable cost of
015: * materials and delivery.
016: *
017: * Redistributions are accompanied by a copy of the Source Code or by an
018: * irrevocable offer to provide a copy of the Source Code for up to three
019: * years at the cost of materials and delivery. Such redistributions
020: * must allow further use, modification, and redistribution of the Source
021: * Code under substantially the same terms as this license.
022: *
023: * Redistributions of source code must retain the copyright notices as they
024: * appear in each source code file, these license terms, and the
025: * disclaimer/limitation of liability set forth as paragraph 6 below.
026: *
027: * Redistributions in binary form must reproduce this Copyright Notice,
028: * these license terms, and the disclaimer/limitation of liability set
029: * forth as paragraph 6 below, in the documentation and/or other materials
030: * provided with the distribution.
031: *
032: * The Software is provided on an "AS IS" basis. No warranty is
033: * provided that the Software is free of defects, or fit for a
034: * particular purpose.
035: *
036: * Limitation of Liability. Quadcap Software shall not be liable
037: * for any damages suffered by the Licensee or any third party resulting
038: * from use of the Software.
039: */
040:
041: import java.io.File;
042: import java.io.FileInputStream;
043: import java.io.FileNotFoundException;
044: import java.io.InputStream;
045: import java.io.IOException;
046: import java.io.OutputStream;
047:
048: import java.net.URL;
049: import java.net.URLConnection;
050:
051: import javax.servlet.ServletContext;
052:
053: import javax.servlet.http.HttpServletRequest;
054: import javax.servlet.http.HttpServletResponse;
055:
056: import com.quadcap.util.collections.Cacheable;
057:
058: import com.quadcap.io.IO;
059:
060: import com.quadcap.io.dir.Directory;
061: import com.quadcap.io.dir.Entry;
062:
063: import com.quadcap.util.Debug;
064: import com.quadcap.util.Util;
065:
066: /**
067: * This class represents a single cached file.
068: *
069: * @author Stan Bailes
070: */
071: public class HttpFile extends Cacheable {
072: ServletContext context;
073: String contentType = "text/plain";
074: File file;
075: URL url;
076: long lastMod;
077: long lastCheck = -1;
078: byte[] buf = null;
079:
080: static int MAX_CACHED = 16 * 1024;
081:
082: /**
083: * Default constructor
084: */
085: public HttpFile() {
086: }
087:
088: public void init(Object store, Object key) throws IOException {
089: super .init(store, key);
090: FileServlet fs = (FileServlet) store;
091: this .context = fs.getServletContext();
092: String path = key.toString();
093: this .contentType = context.getMimeType(path);
094: this .file = new File(path);
095: if (!file.exists()) {
096: this .file = null;
097: this .url = fs.getURL(path);
098: if (url == null) {
099: throw new FileNotFoundException("Not found: " + path);
100: }
101: }
102: compile();
103: }
104:
105: public synchronized void compile() throws IOException {
106: if (file != null) {
107: if (!file.exists()) {
108: throw new FileNotFoundException("Not found: " + file);
109: }
110: if (file.isDirectory()) {
111: File g = new File(file, "index.html");
112: if (g.canRead()) {
113: file = g;
114: contentType = "text/html";
115: } else {
116: throw new FileNotFoundException("Not found: "
117: + file);
118: }
119: }
120: if (file.canRead() && file.length() < MAX_CACHED) {
121: buf = new byte[(int) file.length()];
122: FileInputStream is = new FileInputStream(file);
123: try {
124: IO.readFully(is, buf);
125: } finally {
126: is.close();
127: }
128: this .lastMod = file.lastModified();
129: } else {
130: buf = null;
131: }
132: } else {
133: URLConnection conn = url.openConnection();
134: long len = conn.getContentLength();
135: if (len < MAX_CACHED) {
136: buf = new byte[(int) len];
137: try {
138: this .lastMod = conn.getLastModified();
139: InputStream is = conn.getInputStream();
140: try {
141: IO.readFully(is, buf);
142: } finally {
143: is.close();
144: }
145: } catch (IOException e) {
146: buf = null;
147: throw e;
148: }
149: } else {
150: buf = null;
151: }
152: }
153: }
154:
155: public synchronized void service(HttpServletRequest req,
156: HttpServletResponse res) throws IOException {
157: //Jni j = new Jni("file");
158: res.setContentType(contentType);
159: //j.dump("setContentType");
160: OutputStream os = res.getOutputStream();
161: //j.dump("getOutputStream");
162: if (buf != null) {
163: res.setContentLength(buf.length);
164: //j.dump("setContentLength");
165: os.write(buf);
166: //j.dump("os.write(buf)");
167: } else if (file != null) {
168: res.setContentLength((int) file.length());
169: try {
170: FileInputStream is = new FileInputStream(file);
171: try {
172: IO.copyStream(is, os);
173: } finally {
174: is.close();
175: }
176: } catch (FileNotFoundException fe) {
177: res.sendError(res.SC_NOT_FOUND, "Not found: "
178: + file.getName());
179: }
180: } else {
181: URLConnection conn = url.openConnection();
182: res.setContentLength(conn.getContentLength());
183: InputStream is = conn.getInputStream();
184: try {
185: IO.copyStream(is, os);
186: } finally {
187: is.close();
188: }
189: }
190: //j.dump("done");
191: }
192:
193: public synchronized void checkModified() throws Exception {
194: long now = System.currentTimeMillis();
195: if (now - lastCheck > 2000) {
196: lastCheck = now;
197: if (file != null) {
198: if (file.lastModified() > lastMod) {
199: compile();
200: }
201: } else {
202: URLConnection conn = url.openConnection();
203: if (conn.getLastModified() > lastMod) {
204: compile();
205: }
206: }
207: }
208: }
209:
210: public Object getData() {
211: return this ;
212: }
213:
214: public void setData(Object obj) {
215: throw new RuntimeException("not implemented");
216: }
217: }
|