KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > repo > content > filestore > FileContentStore


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.repo.content.filestore;
18
19 import java.io.File JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.util.Date JavaDoc;
22 import java.util.HashSet JavaDoc;
23 import java.util.Set JavaDoc;
24
25 import org.alfresco.error.AlfrescoRuntimeException;
26 import org.alfresco.repo.content.AbstractContentStore;
27 import org.alfresco.service.cmr.repository.ContentIOException;
28 import org.alfresco.service.cmr.repository.ContentReader;
29 import org.alfresco.service.cmr.repository.ContentWriter;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32
33 /**
34  * Provides a store of node content directly to the file system.
35  * <p>
36  * The file names obey, as they must, the URL naming convention
37  * as specified in the {@link org.alfresco.repo.content.ContentStore}.
38  *
39  * @author Derek Hulley
40  */

41 public class FileContentStore extends AbstractContentStore
42 {
43     private static final Log logger = LogFactory.getLog(FileContentStore.class);
44     
45     private File JavaDoc rootDirectory;
46     private String JavaDoc rootAbsolutePath;
47     private boolean allowRandomAccess;
48
49     /**
50      * @param rootDirectory the root under which files will be stored. The
51      * directory will be created if it does not exist.
52      */

53     public FileContentStore(String JavaDoc rootDirectoryStr)
54     {
55         rootDirectory = new File JavaDoc(rootDirectoryStr);
56         if (!rootDirectory.exists())
57         {
58             if (!rootDirectory.mkdirs())
59             {
60                 throw new ContentIOException("Failed to create store root: " + rootDirectory, null);
61             }
62         }
63         rootDirectory = rootDirectory.getAbsoluteFile();
64         rootAbsolutePath = rootDirectory.getAbsolutePath();
65         allowRandomAccess = true;
66     }
67
68     public String JavaDoc toString()
69     {
70         StringBuilder JavaDoc sb = new StringBuilder JavaDoc(36);
71         sb.append("FileContentStore")
72           .append("[ root=").append(rootDirectory)
73           .append("]");
74         return sb.toString();
75     }
76
77     /**
78      * Stores may optionally produce readers and writers that support random access.
79      * Switch this off for this store by setting this to <tt>false</tt>.
80      * <p>
81      * This switch is primarily used during testing to ensure that the system has the
82      * ability to spoof random access in cases where the store is unable to produce
83      * readers and writers that allow random access. Typically, stream-based access
84      * would be an example.
85      *
86      * @param allowRandomAccess true to allow random access, false to have it faked
87      */

88     public void setAllowRandomAccess(boolean allowRandomAccess)
89     {
90         this.allowRandomAccess = allowRandomAccess;
91     }
92
93     /**
94      * Generates a new URL and file appropriate to it.
95      *
96      * @return Returns a new and unique file
97      * @throws IOException if the file or parent directories couldn't be created
98      */

99     private File JavaDoc createNewFile() throws IOException JavaDoc
100     {
101         String JavaDoc contentUrl = createNewUrl();
102         return createNewFile(contentUrl);
103     }
104     
105     /**
106      * Creates a file for the specifically provided content URL. The URL may
107      * not already be in use.
108      * <p>
109      * The store prefix is stripped off the URL and the rest of the URL
110      * used directly to create a file.
111      *
112      * @param newContentUrl the specific URL to use, which may not be in use
113      * @return Returns a new and unique file
114      * @throws IOException if the file or parent directories couldn't be created or
115      * if the URL is already in use.
116      */

117     public File JavaDoc createNewFile(String JavaDoc newContentUrl) throws IOException JavaDoc
118     {
119         File JavaDoc file = makeFile(newContentUrl);
120
121         // create the directory, if it doesn't exist
122
File JavaDoc dir = file.getParentFile();
123         if (!dir.exists())
124         {
125             dir.mkdirs();
126         }
127         
128         // create a new, empty file
129
boolean created = file.createNewFile();
130         if (!created)
131         {
132             throw new ContentIOException(
133                     "When specifying a URL for new content, the URL may not be in use already. \n" +
134                     " store: " + this + "\n" +
135                     " new URL: " + newContentUrl);
136         }
137         
138         // done
139
return file;
140     }
141     
142     /**
143      * Takes the file absolute path, strips off the root path of the store
144      * and appends the store URL prefix.
145      *
146      * @param file the file from which to create the URL
147      * @return Returns the equivalent content URL
148      * @throws Exception
149      */

150     private String JavaDoc makeContentUrl(File JavaDoc file)
151     {
152         String JavaDoc path = file.getAbsolutePath();
153         // check if it belongs to this store
154
if (!path.startsWith(rootAbsolutePath))
155         {
156             throw new AlfrescoRuntimeException(
157                     "File does not fall below the store's root: \n" +
158                     " file: " + file + "\n" +
159                     " store: " + this);
160         }
161         // strip off the file separator char, if present
162
int index = rootAbsolutePath.length();
163         if (path.charAt(index) == File.separatorChar)
164         {
165             index++;
166         }
167         // strip off the root path and adds the protocol prefix
168
String JavaDoc url = AbstractContentStore.STORE_PROTOCOL + path.substring(index);
169         // replace '\' with '/' so that URLs are consistent across all filesystems
170
url = url.replace('\\', '/');
171         // done
172
return url;
173     }
174     
175     /**
176      * Creates a file from the given relative URL. The URL must start with
177      * the required {@link FileContentStore#STORE_PROTOCOL protocol prefix}.
178      *
179      * @param contentUrl the content URL including the protocol prefix
180      * @return Returns a file representing the URL - the file may or may not
181      * exist
182      *
183      * @see #checkUrl(String)
184      */

185     private File JavaDoc makeFile(String JavaDoc contentUrl)
186     {
187         // take just the part after the protocol
188
String JavaDoc relativeUrl = getRelativePart(contentUrl);
189         // get the file
190
File JavaDoc file = new File JavaDoc(rootDirectory, relativeUrl);
191         // done
192
return file;
193     }
194     
195     /**
196      * Performs a direct check against the file for its existence.
197      */

198     @Override JavaDoc
199     public boolean exists(String JavaDoc contentUrl) throws ContentIOException
200     {
201         File JavaDoc file = makeFile(contentUrl);
202         return file.exists();
203     }
204
205     /**
206      * This implementation requires that the URL start with
207      * {@link FileContentStore#STORE_PROTOCOL }.
208      */

209     public ContentReader getReader(String JavaDoc contentUrl)
210     {
211         try
212         {
213             File JavaDoc file = makeFile(contentUrl);
214             FileContentReader reader = new FileContentReader(file, contentUrl);
215             reader.setAllowRandomAccess(allowRandomAccess);
216             
217             // done
218
if (logger.isDebugEnabled())
219             {
220                 logger.debug("Created content reader: \n" +
221                         " url: " + contentUrl + "\n" +
222                         " file: " + file + "\n" +
223                         " reader: " + reader);
224             }
225             return reader;
226         }
227         catch (Throwable JavaDoc e)
228         {
229             throw new ContentIOException("Failed to get reader for URL: " + contentUrl, e);
230         }
231     }
232     
233     /**
234      * @return Returns a writer onto a location based on the date
235      */

236     public ContentWriter getWriter(ContentReader existingContentReader, String JavaDoc newContentUrl)
237     {
238         try
239         {
240             File JavaDoc file = null;
241             String JavaDoc contentUrl = null;
242             if (newContentUrl == null) // a specific URL was not supplied
243
{
244                 // get a new file with a new URL
245
file = createNewFile();
246                 // make a URL
247
contentUrl = makeContentUrl(file);
248             }
249             else // the URL has been given
250
{
251                 file = createNewFile(newContentUrl);
252                 contentUrl = newContentUrl;
253             }
254             // create the writer
255
FileContentWriter writer = new FileContentWriter(file, contentUrl, existingContentReader);
256             writer.setAllowRandomAccess(allowRandomAccess);
257             
258             // done
259
if (logger.isDebugEnabled())
260             {
261                 logger.debug("Created content writer: \n" +
262                         " writer: " + writer);
263             }
264             return writer;
265         }
266         catch (IOException JavaDoc e)
267         {
268             throw new ContentIOException("Failed to get writer", e);
269         }
270     }
271
272     public Set JavaDoc<String JavaDoc> getUrls(Date JavaDoc createdAfter, Date JavaDoc createdBefore)
273     {
274         // recursively get all files within the root
275
Set JavaDoc<String JavaDoc> contentUrls = new HashSet JavaDoc<String JavaDoc>(1000);
276         getUrls(rootDirectory, contentUrls, createdAfter, createdBefore);
277         // done
278
if (logger.isDebugEnabled())
279         {
280             logger.debug("Listed all content URLS: \n" +
281                     " store: " + this + "\n" +
282                     " count: " + contentUrls.size());
283         }
284         return contentUrls;
285     }
286     
287     /**
288      * @param directory the current directory to get the files from
289      * @param contentUrls the list of current content URLs to add to
290      * @param createdAfter only get URLs for content create after this date
291      * @param createdBefore only get URLs for content created before this date
292      * @return Returns a list of all files within the given directory and all subdirectories
293      */

294     private void getUrls(File JavaDoc directory, Set JavaDoc<String JavaDoc> contentUrls, Date JavaDoc createdAfter, Date JavaDoc createdBefore)
295     {
296         File JavaDoc[] files = directory.listFiles();
297         if (files == null)
298         {
299             // the directory has disappeared
300
throw new ContentIOException("Failed list files in folder: " + directory);
301         }
302         for (File JavaDoc file : files)
303         {
304             if (file.isDirectory())
305             {
306                 // we have a subdirectory - recurse
307
getUrls(file, contentUrls, createdAfter, createdBefore);
308             }
309             else
310             {
311                 // check the created date of the file
312
long lastModified = file.lastModified();
313                 if (createdAfter != null && lastModified < createdAfter.getTime())
314                 {
315                     // file is too old
316
continue;
317                 }
318                 else if (createdBefore != null && lastModified > createdBefore.getTime())
319                 {
320                     // file is too young
321
continue;
322                 }
323                 // found a file - create the URL
324
String JavaDoc contentUrl = makeContentUrl(file);
325                 contentUrls.add(contentUrl);
326             }
327         }
328     }
329     
330     /**
331      * Attempts to delete the content. The actual deletion is optional on the interface
332      * so it just returns the success or failure of the underlying delete.
333      */

334     public boolean delete(String JavaDoc contentUrl) throws ContentIOException
335     {
336         // ignore files that don't exist
337
File JavaDoc file = makeFile(contentUrl);
338         boolean deleted = false;
339         if (!file.exists())
340         {
341             deleted = true;
342         }
343         else
344         {
345             deleted = file.delete();
346         }
347
348         // done
349
if (logger.isDebugEnabled())
350         {
351             logger.debug("Delete content directly: \n" +
352                     " store: " + this + "\n" +
353                     " url: " + contentUrl);
354         }
355         return deleted;
356     }
357 }
358
Popular Tags