001: /* *****************************************************************************
002: * FileDataSource.java
003: * ****************************************************************************/
004:
005: /* J_LZ_COPYRIGHT_BEGIN *******************************************************
006: * Copyright 2001-2004 Laszlo Systems, Inc. All Rights Reserved. *
007: * Use is subject to license terms. *
008: * J_LZ_COPYRIGHT_END *********************************************************/
009:
010: package org.openlaszlo.data;
011:
012: import java.io.*;
013: import java.net.URL;
014: import java.net.MalformedURLException;
015: import javax.servlet.http.HttpServletRequest;
016: import javax.servlet.http.HttpServletResponse;
017: import org.apache.log4j.Logger;
018: import org.openlaszlo.utils.ChainedException;
019: import org.openlaszlo.utils.LZHttpUtils;
020: import org.openlaszlo.utils.FileUtils;
021: import org.openlaszlo.media.MimeType;
022:
023: /**
024: * File Transport
025: */
026: public class FileDataSource extends DataSource {
027: private static Logger mLogger = Logger
028: .getLogger(FileDataSource.class);
029:
030: /**
031: * @return name
032: */
033: public String name() {
034: return "file";
035: }
036:
037: /**
038: * @return the data from this request
039: * @param app absolute pathnane to app file
040: * @param req request in progress
041: * @param lastModifiedTime this is the timestamp on the
042: * currently cached item; this time can be used as the datasource
043: * sees fit (or ignored) in constructing the results. If
044: * the value is -1, assume there is no currently cached item.
045: */
046: public Data getData(String app, HttpServletRequest req,
047: HttpServletResponse res, long lastModifiedTime)
048: throws IOException, DataSourceException {
049: return getFileData(app, req, res, null, lastModifiedTime);
050: }
051:
052: static public Data getFileData(String app, HttpServletRequest req,
053: HttpServletResponse res, String urlStr,
054: long lastModifiedTime) throws IOException,
055: DataSourceException {
056:
057: if (urlStr == null) {
058: urlStr = DataSource.getURL(req);
059: }
060:
061: URL url = new URL(urlStr);
062:
063: String protocol = url.getProtocol();
064:
065: if (protocol == null || !protocol.equals("file")) {
066: mLogger.error(
067: /* (non-Javadoc)
068: * @i18n.test
069: * @org-mes="bad protocol for " + p[0]
070: */
071: org.openlaszlo.i18n.LaszloMessages.getMessage(
072: FileDataSource.class.getName(), "051018-71",
073: new Object[] { url }));
074: throw new DataSourceException(
075: /* (non-Javadoc)
076: * @i18n.test
077: * @org-mes="protocol " + p[0] + "is not 'file:' "
078: */
079: org.openlaszlo.i18n.LaszloMessages.getMessage(
080: FileDataSource.class.getName(), "051018-79",
081: new Object[] { protocol }));
082: }
083:
084: // We are not supporting 'file' type requests anymore.
085: if (true) {
086: throw new IOException(
087: /* (non-Javadoc)
088: * @i18n.test
089: * @org-mes="'file' data request type is not supported."
090: */
091: org.openlaszlo.i18n.LaszloMessages.getMessage(
092: FileDataSource.class.getName(), "051018-91"));
093: }
094:
095: String filename = url.getFile();
096: mLogger.debug("filename " + filename);
097:
098: if (filename == null || filename.equals("")) {
099: throw new DataSourceException(
100: /* (non-Javadoc)
101: * @i18n.test
102: * @org-mes="empty filename"
103: */
104: org.openlaszlo.i18n.LaszloMessages.getMessage(
105: FileDataSource.class.getName(), "051018-105"));
106: }
107:
108: // For relative urls, add app path before
109: if (filename.charAt(0) != '/') {
110: mLogger.debug(
111: /* (non-Javadoc)
112: * @i18n.test
113: * @org-mes="app " + p[0]
114: */
115: org.openlaszlo.i18n.LaszloMessages.getMessage(
116: FileDataSource.class.getName(), "051018-117",
117: new Object[] { app }));
118: String appdir = app.substring(0, app
119: .lastIndexOf(File.separatorChar) + 1);
120: mLogger.debug(
121: /* (non-Javadoc)
122: * @i18n.test
123: * @org-mes="appdir " + p[0]
124: */
125: org.openlaszlo.i18n.LaszloMessages.getMessage(
126: FileDataSource.class.getName(), "051018-127",
127: new Object[] { appdir }));
128: filename = appdir + filename;
129: mLogger.debug(
130: /* (non-Javadoc)
131: * @i18n.test
132: * @org-mes="filename " + p[0]
133: */
134: org.openlaszlo.i18n.LaszloMessages.getMessage(
135: FileDataSource.class.getName(), "051018-136",
136: new Object[] { filename }));
137: }
138:
139: // Cope with Windows wackiness.
140: if (File.separatorChar == '\\') {
141: while (filename.startsWith("/")) {
142: filename = filename.substring(1);
143: }
144: filename = filename.replace('/', '\\');
145: }
146:
147: FileData data = new FileData(filename, lastModifiedTime);
148:
149: // proxy date header
150: res.setDateHeader(LZHttpUtils.LAST_MODIFIED, data
151: .lastModified());
152:
153: return data;
154: }
155:
156: /**
157: * A class for holding on to results of a File fetch.
158: *
159: * @author <a href="mailto:bloch@laszlosystems.com">Eric Bloch</a>
160: */
161:
162: public static class FileData extends Data {
163:
164: /** response code */
165: public FileInputStream str = null;
166:
167: /** file */
168: public final File file;
169:
170: /** lastModifiedTime from request (or -1)*/
171: public final long lastModifiedTime;
172:
173: /**
174: * @param f file
175: */
176: public FileData(String filename, long lm) throws IOException {
177: mLogger.debug(
178: /* (non-Javadoc)
179: * @i18n.test
180: * @org-mes="filename " + p[0]
181: */
182: org.openlaszlo.i18n.LaszloMessages.getMessage(
183: FileDataSource.class.getName(), "051018-136",
184: new Object[] { filename }));
185: File f = new File(filename);
186: if (f == null) {
187: throw new IOException(
188: /* (non-Javadoc)
189: * @i18n.test
190: * @org-mes="can't construct file"
191: */
192: org.openlaszlo.i18n.LaszloMessages.getMessage(
193: FileDataSource.class.getName(), "051018-193"));
194: } else if (!f.exists()) {
195: throw new IOException(
196: /* (non-Javadoc)
197: * @i18n.test
198: * @org-mes=p[0] + " doesn't exist."
199: */
200: org.openlaszlo.i18n.LaszloMessages.getMessage(
201: FileDataSource.class.getName(), "051018-202",
202: new Object[] { filename }));
203: } else if (!f.canRead()) {
204: throw new IOException(
205: /* (non-Javadoc)
206: * @i18n.test
207: * @org-mes="can't read " + p[0]
208: */
209: org.openlaszlo.i18n.LaszloMessages.getMessage(
210: FileDataSource.class.getName(), "051018-211",
211: new Object[] { filename }));
212: }
213: lastModifiedTime = lm;
214: file = f;
215: }
216:
217: /**
218: * @return size of file
219: */
220: public long size() {
221: try {
222: return FileUtils.fileSize(file);
223: } catch (Exception e) {
224: throw new ChainedException(e);
225: }
226: }
227:
228: /**
229: * @return true if the data was "not modified"
230: * compared to the cached lastModified time.
231: */
232: public boolean notModified() {
233:
234: long l = lastModified();
235: if (l == -1) {
236: return false;
237: }
238:
239: return (l <= lastModifiedTime);
240: }
241:
242: /**
243: * @return the lastModified time of the data
244: */
245: public long lastModified() {
246:
247: long l = file.lastModified();
248: if (l == 0) {
249: l = -1;
250: }
251: // Truncate to nearest second
252: l = ((l) / 1000L) * 1000L;
253: mLogger.debug("lm is " + l);
254: return l;
255: }
256:
257: /**
258: * append response headers
259: */
260: public void appendResponseHeadersAsXML(StringBuffer xmlResponse) {
261: // TODO: [2003-04-17 bloch] should this be a string or a long?
262: xmlResponse.append("<header name=\"Last-Modified\" "
263: + "value=\"" + lastModified() + "\" />");
264: }
265:
266: /**
267: * release any resources associated with this data
268: */
269: public synchronized void release() {
270: try {
271: if (str != null) {
272: str.close();
273: str = null;
274: }
275: } catch (Exception e) {
276: mLogger.warn(
277: /* (non-Javadoc)
278: * @i18n.test
279: * @org-mes="ignoring exception while closing stream: "
280: */
281: org.openlaszlo.i18n.LaszloMessages.getMessage(
282: FileDataSource.class.getName(), "051018-283"),
283: e);
284: }
285: }
286:
287: /**
288: * @return mime type
289: */
290: public String getMimeType() {
291: return MimeType.fromExtension(file.getPath());
292: }
293:
294: /**
295: * @return input stream
296: */
297: public synchronized InputStream getInputStream()
298: throws IOException {
299: if (str == null) {
300: str = new FileInputStream(file);
301: }
302: return str;
303: }
304:
305: /**
306: * @return string
307: */
308: public String getAsString() throws IOException {
309: return FileUtils.readFileString(file);
310: }
311: }
312: }
|