View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.vfs.impl;
18  
19  import org.apache.commons.logging.Log;
20  import org.apache.commons.logging.LogFactory;
21  import org.apache.commons.vfs.FileObject;
22  import org.apache.commons.vfs.FileSelector;
23  import org.apache.commons.vfs.FileSystemException;
24  import org.apache.commons.vfs.Selectors;
25  import org.apache.commons.vfs.VfsLog;
26  import org.apache.commons.vfs.provider.AbstractVfsComponent;
27  import org.apache.commons.vfs.provider.FileReplicator;
28  import org.apache.commons.vfs.provider.TemporaryFileStore;
29  import org.apache.commons.vfs.provider.UriParser;
30  import org.apache.commons.vfs.util.Messages;
31  
32  import java.io.File;
33  import java.util.ArrayList;
34  import java.util.Random;
35  
36  /***
37   * A simple file replicator and temporary file store.
38   *
39   * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a>
40   * @version $Revision: 480428 $ $Date: 2006-11-29 07:15:24 +0100 (Mi, 29 Nov 2006) $
41   */
42  public class DefaultFileReplicator
43      extends AbstractVfsComponent
44      implements FileReplicator, TemporaryFileStore
45  {
46      private final static Log log = LogFactory.getLog(DefaultFileReplicator.class);
47  
48      private final ArrayList copies = new ArrayList();
49      private File tempDir;
50      private long filecount;
51      private boolean tempDirMessageLogged;
52  
53      private char[] TMP_RESERVED_CHARS = new char[]
54          {
55              '?', '/', '//', ' ', '&', '"', '\'', '*', '#', ';', ':', '<', '>', '|'
56          };
57  
58      /***
59       * constructor to set the location of the temporary directory
60       *
61       * @param tempDir
62       */
63      public DefaultFileReplicator(final File tempDir)
64      {
65          this.tempDir = tempDir;
66      }
67  
68      public DefaultFileReplicator()
69      {
70      }
71  
72      /***
73       * Initialises this component.
74       */
75      public void init() throws FileSystemException
76      {
77          if (tempDir == null)
78          {
79              String baseTmpDir = System.getProperty("java.io.tmpdir");
80  
81              tempDir = new File(baseTmpDir, "vfs_cache").getAbsoluteFile();
82          }
83  
84          filecount = new Random().nextInt() & 0xffff;
85  
86          if (!tempDirMessageLogged)
87          {
88              final String message = Messages.getString("vfs.impl/temp-dir.info", tempDir);
89              VfsLog.info(getLogger(), log, message);
90  
91              tempDirMessageLogged = true;
92          }
93      }
94  
95      /***
96       * Closes the replicator, deleting all temporary files.
97       */
98      public void close()
99      {
100         // Delete the temporary files
101         synchronized (copies)
102         {
103             while (copies.size() > 0)
104             {
105                 final File file = (File) removeFile();
106                 deleteFile(file);
107             }
108         }
109 
110         // Clean up the temp directory, if it is empty
111         if (tempDir != null && tempDir.exists() && tempDir.list().length == 0)
112         {
113             tempDir.delete();
114             tempDir = null;
115         }
116     }
117 
118     /***
119      * physically deletes the file from the filesystem
120      */
121     protected void deleteFile(File file)
122     {
123         try
124         {
125             final FileObject fileObject = getContext().toFileObject(file);
126             fileObject.delete(Selectors.SELECT_ALL);
127         }
128         catch (final FileSystemException e)
129         {
130             final String message = Messages.getString("vfs.impl/delete-temp.warn", file.getName());
131             VfsLog.warn(getLogger(), log, message, e);
132         }
133     }
134 
135     /***
136      * removes a file from the copies list. Will be used for cleanup. <br/>
137      * Notice: The system awaits that the returning object can be cast to a java.io.File
138      */
139     protected Object removeFile()
140     {
141         synchronized (copies)
142         {
143             return copies.remove(0);
144         }
145     }
146 
147     /***
148      * removes a instance from the list of copies
149      */
150     protected void removeFile(Object file)
151     {
152         synchronized (copies)
153         {
154             copies.remove(file);
155         }
156     }
157 
158     /***
159      * Allocates a new temporary file.
160      */
161     public File allocateFile(final String baseName) throws FileSystemException
162     {
163         // Create a unique-ish file name
164         final String basename = createFilename(baseName);
165         synchronized (this)
166         {
167             filecount++;
168         }
169 
170         final File file = createAndAddFile(tempDir, basename);
171 
172         return file;
173     }
174 
175     protected File createAndAddFile(final File parent, final String basename) throws FileSystemException
176     {
177         final File file = createFile(tempDir, basename);
178 
179         // Keep track to delete later
180         addFile(file);
181 
182         return file;
183     }
184 
185     protected void addFile(Object file)
186     {
187         synchronized (copies)
188         {
189             copies.add(file);
190         }
191     }
192 
193     protected long getFilecount()
194     {
195         return filecount;
196     }
197 
198     /***
199      * create the temporary file name
200      */
201     protected String createFilename(final String baseName)
202     {
203         // BUG29007
204         // return baseName + "_" + getFilecount() + ".tmp";
205 
206         // imario@apache.org: BUG34976 get rid of maybe reserved and dangerous characters
207         // e.g. to allow replication of http://hostname.org/fileservlet?file=abc.txt
208         String safeBasename = UriParser.encode(baseName, TMP_RESERVED_CHARS).replace('%', '_');
209         return "tmp_" + getFilecount() + "_" + safeBasename;
210     }
211 
212     /***
213      * create the temporary file
214      */
215     protected File createFile(final File parent, final String name) throws FileSystemException
216     {
217         return new File(parent, UriParser.decode(name));
218     }
219 
220     /***
221      * Creates a local copy of the file, and all its descendents.
222      */
223     public File replicateFile(final FileObject srcFile,
224                               final FileSelector selector)
225         throws FileSystemException
226     {
227         final String basename = srcFile.getName().getBaseName();
228         final File file = allocateFile(basename);
229 
230         // Copy from the source file
231         final FileObject destFile = getContext().toFileObject(file);
232         destFile.copyFrom(srcFile, selector);
233 
234         return file;
235     }
236 }