001: /*
002: * Copyright 2005 Joe Walker
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.directwebremoting.impl;
017:
018: import java.io.File;
019: import java.io.FileFilter;
020: import java.io.FileInputStream;
021: import java.io.FileOutputStream;
022: import java.io.IOException;
023: import java.io.InputStream;
024: import java.io.OutputStream;
025:
026: import org.directwebremoting.Container;
027: import org.directwebremoting.extend.DownloadManager;
028: import org.directwebremoting.extend.FileGenerator;
029: import org.directwebremoting.extend.InitializingBean;
030: import org.directwebremoting.util.LocalUtil;
031:
032: /**
033: * A {@link DownloadManager} that stores the files on disk.
034: * This implementation has the advantage that does not require large amounts of
035: * memory, however some writable disk must be available, and
036: * @author Joe Walker [joe at getahead dot ltd dot uk]
037: */
038: public class FileStoreDownloadManager extends PurgingDownloadManager
039: implements DownloadManager, InitializingBean {
040: /* (non-Javadoc)
041: * @see org.directwebremoting.extend.InitializingBean#afterContainerSetup(org.directwebremoting.Container)
042: */
043: public void afterContainerSetup(Container container) {
044: if (downloadFileCache == null) {
045: File tempFile = null;
046: OutputStream out = null;
047:
048: try {
049: tempFile = File.createTempFile("dwr-test", ".tmp");
050: out = new FileOutputStream(tempFile);
051: out.write("test".getBytes());
052:
053: // Get the temp directory from the location of the temp file
054: downloadFileCache = tempFile.getParentFile();
055: if (downloadFileCache == null) {
056: throw new IllegalArgumentException(
057: "Temp files written to null directory");
058: }
059: } catch (IOException ex) {
060: throw new IllegalArgumentException(
061: "Temp directory provided by the JVM is not writable. See downloadFileCacheDir to customize.");
062: } finally {
063: LocalUtil.close(out);
064: if (tempFile != null) {
065: tempFile.delete();
066: }
067: }
068: }
069: }
070:
071: /* (non-Javadoc)
072: * @see org.directwebremoting.impl.PurgingDownloadManager#putFileGenerator(java.lang.String, org.directwebremoting.extend.DownloadManager.FileGenerator)
073: */
074: @Override
075: protected void putFileGenerator(String id, FileGenerator generator) {
076: String filename = FILE_PREFIX + PART_SEPARATOR + id
077: + PART_SEPARATOR
078: + generator.getMimeType().replace("/", ".")
079: + PART_SEPARATOR + generator.getFilename();
080:
081: OutputStream out = null;
082: try {
083: out = new FileOutputStream(filename);
084: generator.generateFile(out);
085: out.close();
086: } catch (IOException ex) {
087: log.error("Failed to write file to cache", ex);
088: } finally {
089: LocalUtil.close(out);
090: }
091: }
092:
093: /* (non-Javadoc)
094: * @see org.directwebremoting.impl.PurgingDownloadManager#getFileGenerator(java.lang.String)
095: */
096: @Override
097: protected FileGenerator getFileGenerator(String id) {
098: final String prefix = FILE_PREFIX + PART_SEPARATOR + id
099: + PART_SEPARATOR;
100:
101: final File[] match = downloadFileCache
102: .listFiles(new FileFilter() {
103: /* (non-Javadoc)
104: * @see java.io.FileFilter#accept(java.io.File, java.lang.String)
105: */
106: public boolean accept(File file) {
107: return file.getName().startsWith(prefix);
108: }
109: });
110:
111: if (match.length == 0) {
112: return null;
113: }
114:
115: if (match.length > 1) {
116: log.warn("More than 1 match for prefix: " + prefix
117: + ". Using first.");
118: }
119:
120: String[] parts = match[0].getName().split(PART_SEPARATOR, 4);
121:
122: // Parts 0 and 1 are the prefix and id. We know they're right
123: String mimeType = parts[2].replace(".", "/");
124: String filename = parts[3];
125:
126: return new AbstractFileGenerator(filename, mimeType) {
127: /* (non-Javadoc)
128: * @see org.directwebremoting.extend.DownloadManager.FileGenerator#generateFile(java.io.OutputStream)
129: */
130: public void generateFile(OutputStream out)
131: throws IOException {
132: InputStream in = null;
133: try {
134: in = new FileInputStream(match[0]);
135: byte[] buffer = new byte[1024];
136:
137: while (true) {
138: int len = in.read(buffer);
139: if (len == 0) {
140: break;
141: }
142: out.write(buffer, 0, len);
143: }
144: } finally {
145: LocalUtil.close(in);
146: match[0].delete();
147: }
148: }
149: };
150: }
151:
152: /* (non-Javadoc)
153: * @see org.directwebremoting.impl.PurgingDownloadManager#purge()
154: */
155: @Override
156: protected void purge() {
157: final long now = System.currentTimeMillis();
158:
159: final File[] match = downloadFileCache
160: .listFiles(new FileFilter() {
161: /* (non-Javadoc)
162: * @see java.io.FileFilter#accept(java.io.File)
163: */
164: public boolean accept(File file) {
165: boolean nameMatch = file.getName().startsWith(
166: FILE_PREFIX);
167: boolean oldEnough = now > file.lastModified()
168: + purgeDownloadsAfter;
169: return nameMatch && oldEnough;
170: }
171: });
172:
173: for (File file : match) {
174: file.delete();
175: }
176: }
177:
178: /**
179: * Set the directory to which we write the downloaded file cache
180: * @param downloadFileCacheDir the downloadFileCache to set
181: */
182: public void setDownloadFileCacheDir(String downloadFileCacheDir) {
183: downloadFileCache = new File(downloadFileCacheDir);
184:
185: if (!downloadFileCache.exists()) {
186: throw new IllegalArgumentException(
187: "Download cache does not exist: "
188: + downloadFileCacheDir);
189: }
190:
191: if (!downloadFileCache.isDirectory()) {
192: throw new IllegalArgumentException(
193: "Download cache is not a directory: "
194: + downloadFileCacheDir);
195: }
196: }
197:
198: /**
199: * The prefix for all temp files that we save
200: */
201: private static final String FILE_PREFIX = "dwr";
202:
203: /**
204: * The separator to distinguish the prefix, from the id, the mime-type and
205: * the filename
206: */
207: private static final String PART_SEPARATOR = "-";
208:
209: /**
210: * The lock which you must hold to read or write from the list of
211: * {@link FileGenerator}s.
212: */
213: protected Object contentsLock = new Object();
214:
215: /**
216: * The directory in which we store temp files.
217: */
218: protected File downloadFileCache = null;
219: }
|