001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.commons.vfs.impl;
018:
019: import org.apache.commons.logging.Log;
020: import org.apache.commons.logging.LogFactory;
021: import org.apache.commons.vfs.FileObject;
022: import org.apache.commons.vfs.FileSelector;
023: import org.apache.commons.vfs.FileSystemException;
024: import org.apache.commons.vfs.Selectors;
025: import org.apache.commons.vfs.VfsLog;
026: import org.apache.commons.vfs.provider.AbstractVfsComponent;
027: import org.apache.commons.vfs.provider.FileReplicator;
028: import org.apache.commons.vfs.provider.TemporaryFileStore;
029: import org.apache.commons.vfs.provider.UriParser;
030: import org.apache.commons.vfs.util.Messages;
031:
032: import java.io.File;
033: import java.util.ArrayList;
034: import java.util.Random;
035:
036: /**
037: * A simple file replicator and temporary file store.
038: *
039: * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a>
040: * @version $Revision: 480428 $ $Date: 2006-11-28 22:15:24 -0800 (Tue, 28 Nov 2006) $
041: */
042: public class DefaultFileReplicator extends AbstractVfsComponent
043: implements FileReplicator, TemporaryFileStore {
044: private final static Log log = LogFactory
045: .getLog(DefaultFileReplicator.class);
046:
047: private final ArrayList copies = new ArrayList();
048: private File tempDir;
049: private long filecount;
050: private boolean tempDirMessageLogged;
051:
052: private char[] TMP_RESERVED_CHARS = new char[] { '?', '/', '\\',
053: ' ', '&', '"', '\'', '*', '#', ';', ':', '<', '>', '|' };
054:
055: /**
056: * constructor to set the location of the temporary directory
057: *
058: * @param tempDir
059: */
060: public DefaultFileReplicator(final File tempDir) {
061: this .tempDir = tempDir;
062: }
063:
064: public DefaultFileReplicator() {
065: }
066:
067: /**
068: * Initialises this component.
069: */
070: public void init() throws FileSystemException {
071: if (tempDir == null) {
072: String baseTmpDir = System.getProperty("java.io.tmpdir");
073:
074: tempDir = new File(baseTmpDir, "vfs_cache")
075: .getAbsoluteFile();
076: }
077:
078: filecount = new Random().nextInt() & 0xffff;
079:
080: if (!tempDirMessageLogged) {
081: final String message = Messages.getString(
082: "vfs.impl/temp-dir.info", tempDir);
083: VfsLog.info(getLogger(), log, message);
084:
085: tempDirMessageLogged = true;
086: }
087: }
088:
089: /**
090: * Closes the replicator, deleting all temporary files.
091: */
092: public void close() {
093: // Delete the temporary files
094: synchronized (copies) {
095: while (copies.size() > 0) {
096: final File file = (File) removeFile();
097: deleteFile(file);
098: }
099: }
100:
101: // Clean up the temp directory, if it is empty
102: if (tempDir != null && tempDir.exists()
103: && tempDir.list().length == 0) {
104: tempDir.delete();
105: tempDir = null;
106: }
107: }
108:
109: /**
110: * physically deletes the file from the filesystem
111: */
112: protected void deleteFile(File file) {
113: try {
114: final FileObject fileObject = getContext().toFileObject(
115: file);
116: fileObject.delete(Selectors.SELECT_ALL);
117: } catch (final FileSystemException e) {
118: final String message = Messages.getString(
119: "vfs.impl/delete-temp.warn", file.getName());
120: VfsLog.warn(getLogger(), log, message, e);
121: }
122: }
123:
124: /**
125: * removes a file from the copies list. Will be used for cleanup. <br/>
126: * Notice: The system awaits that the returning object can be cast to a java.io.File
127: */
128: protected Object removeFile() {
129: synchronized (copies) {
130: return copies.remove(0);
131: }
132: }
133:
134: /**
135: * removes a instance from the list of copies
136: */
137: protected void removeFile(Object file) {
138: synchronized (copies) {
139: copies.remove(file);
140: }
141: }
142:
143: /**
144: * Allocates a new temporary file.
145: */
146: public File allocateFile(final String baseName)
147: throws FileSystemException {
148: // Create a unique-ish file name
149: final String basename = createFilename(baseName);
150: synchronized (this ) {
151: filecount++;
152: }
153:
154: final File file = createAndAddFile(tempDir, basename);
155:
156: return file;
157: }
158:
159: protected File createAndAddFile(final File parent,
160: final String basename) throws FileSystemException {
161: final File file = createFile(tempDir, basename);
162:
163: // Keep track to delete later
164: addFile(file);
165:
166: return file;
167: }
168:
169: protected void addFile(Object file) {
170: synchronized (copies) {
171: copies.add(file);
172: }
173: }
174:
175: protected long getFilecount() {
176: return filecount;
177: }
178:
179: /**
180: * create the temporary file name
181: */
182: protected String createFilename(final String baseName) {
183: // BUG29007
184: // return baseName + "_" + getFilecount() + ".tmp";
185:
186: // imario@apache.org: BUG34976 get rid of maybe reserved and dangerous characters
187: // e.g. to allow replication of http://hostname.org/fileservlet?file=abc.txt
188: String safeBasename = UriParser.encode(baseName,
189: TMP_RESERVED_CHARS).replace('%', '_');
190: return "tmp_" + getFilecount() + "_" + safeBasename;
191: }
192:
193: /**
194: * create the temporary file
195: */
196: protected File createFile(final File parent, final String name)
197: throws FileSystemException {
198: return new File(parent, UriParser.decode(name));
199: }
200:
201: /**
202: * Creates a local copy of the file, and all its descendents.
203: */
204: public File replicateFile(final FileObject srcFile,
205: final FileSelector selector) throws FileSystemException {
206: final String basename = srcFile.getName().getBaseName();
207: final File file = allocateFile(basename);
208:
209: // Copy from the source file
210: final FileObject destFile = getContext().toFileObject(file);
211: destFile.copyFrom(srcFile, selector);
212:
213: return file;
214: }
215: }
|