1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jetspeed.page.document.psml;
18
19 import java.io.File;
20 import java.io.FileNotFoundException;
21 import java.io.FilenameFilter;
22 import java.util.ArrayList;
23 import java.util.Iterator;
24 import java.util.List;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.apache.jetspeed.cache.file.FileCache;
29 import org.apache.jetspeed.cache.file.FileCacheEntry;
30 import org.apache.jetspeed.cache.file.FileCacheEventListener;
31 import org.apache.jetspeed.om.folder.Folder;
32 import org.apache.jetspeed.om.folder.FolderNotFoundException;
33 import org.apache.jetspeed.om.folder.InvalidFolderException;
34 import org.apache.jetspeed.om.folder.Reset;
35 import org.apache.jetspeed.om.folder.psml.FolderImpl;
36 import org.apache.jetspeed.om.folder.psml.FolderMetaDataImpl;
37 import org.apache.jetspeed.om.page.Document;
38
39 import org.apache.jetspeed.page.document.DocumentHandler;
40 import org.apache.jetspeed.page.document.DocumentHandlerFactory;
41 import org.apache.jetspeed.page.document.DocumentNotFoundException;
42 import org.apache.jetspeed.page.document.FailedToDeleteFolderException;
43 import org.apache.jetspeed.page.document.FailedToUpdateFolderException;
44 import org.apache.jetspeed.page.document.FolderHandler;
45 import org.apache.jetspeed.page.document.Node;
46 import org.apache.jetspeed.page.document.NodeException;
47 import org.apache.jetspeed.page.document.NodeSet;
48 import org.apache.jetspeed.page.document.UnsupportedDocumentTypeException;
49
50 /***
51 * <p>
52 * FileSystemFolderHandler
53 * </p>
54 * <p>
55 * Implementation of <code>FolderHanlder</code> that is based off of the file
56 * system.
57 * </p>
58 *
59 * @author <a href="mailto:weaver@apache.org">Scott T. Weaver </a>
60 * @version $Id: FileSystemFolderHandler.java 553584 2007-07-05 18:09:45Z taylor $
61 *
62 */
63 public class FileSystemFolderHandler implements FolderHandler, FileCacheEventListener
64 {
65
66 private File documentRootDir;
67 private DocumentHandler metadataDocHandler;
68 private DocumentHandlerFactory handlerFactory;
69
70 private final static Log log = LogFactory.getLog(FileSystemFolderHandler.class);
71
72 protected static final FilenameFilter FOLDER_FILTER = new FilenameFilter()
73 {
74
75 public boolean accept( File pathname, String fileName )
76 {
77 return new File(pathname, fileName).isDirectory();
78 }
79
80 };
81 private FileCache fileCache;
82
83 /***
84 *
85 * @param documentRoot
86 * directory on file system to use as the root when locating
87 * folders
88 * @param handlerFactory
89 * A <code>DocumentHandlerFactory</code>
90 * @param fileCache
91 * For caching folder instances
92 * @throws FileNotFoundException
93 * if the <code>documentRoot</code> does not exist
94 * @throws UnsupportedDocumentTypeException
95 * if no <code>DocumentHnadler</code> could be found that
96 * supports folder metadata (folder.metadata) in the
97 * <code>handlerFactory</code>.
98 */
99 public FileSystemFolderHandler( String documentRoot, DocumentHandlerFactory handlerFactory, FileCache fileCache )
100 throws FileNotFoundException, UnsupportedDocumentTypeException
101 {
102 super();
103 this.documentRootDir = new File(documentRoot);
104 verifyPath(documentRootDir);
105 this.handlerFactory = handlerFactory;
106 this.metadataDocHandler = handlerFactory.getDocumentHandler(FolderMetaDataImpl.DOCUMENT_TYPE);
107 this.fileCache = fileCache;
108 this.fileCache.addListener(this);
109 }
110
111 /***
112 * <p>
113 * getFolder
114 * </p>
115 *
116 * @see org.apache.jetspeed.page.document.FolderHandler#getFolder(java.lang.String)
117 * @param path
118 * @return @throws
119 * FolderNotFoundException
120 * @throws FolderNotFoundException
121 * @throws InvalidFolderException
122 * @throws NodeException
123 * @throws DocumentNotFoundException
124 */
125 public Folder getFolder( String path ) throws FolderNotFoundException, InvalidFolderException, NodeException
126 {
127
128 return getFolder(path, true);
129 }
130
131 protected void verifyPath( File path ) throws FileNotFoundException
132 {
133 if (path == null)
134 {
135 throw new IllegalArgumentException("Page root cannot be null");
136 }
137
138 if (!path.exists())
139 {
140 throw new FileNotFoundException("Could not locate root pages path " + path.getAbsolutePath());
141 }
142 }
143
144 /***
145 * <p>
146 * getFolder
147 * </p>
148 *
149 * @see org.apache.jetspeed.page.document.FolderHandler#getFolder(java.lang.String,
150 * boolean)
151 * @param path
152 * @param fromCache
153 * @return @throws
154 * DocumentException, FolderNotFoundException
155 * @throws InvalidFolderException
156 * @throws DocumentNotFoundException
157 */
158 public Folder getFolder( String path, boolean fromCache ) throws NodeException, FolderNotFoundException, InvalidFolderException
159 {
160 Folder folder = null;
161 File folderFile = new File(documentRootDir, path);
162 if(!folderFile.exists())
163 {
164 throw new FolderNotFoundException(folderFile.getAbsolutePath()+" does not exist.");
165 }
166
167 if(!folderFile.isDirectory())
168 {
169 throw new InvalidFolderException(folderFile.getAbsolutePath()+" is not a valid directory.");
170 }
171
172
173 if (!path.equals(Folder.PATH_SEPARATOR) && path.endsWith(Folder.PATH_SEPARATOR))
174 {
175 path = path.substring(0, path.length()-1);
176 }
177
178
179 if (fromCache)
180 {
181 folder = (Folder) fileCache.getDocument(path);
182 }
183
184
185 if (folder == null)
186 {
187 try
188 {
189
190 FolderMetaDataImpl metadata = (FolderMetaDataImpl) metadataDocHandler.getDocument(path + Folder.PATH_SEPARATOR + FolderMetaDataImpl.DOCUMENT_TYPE);
191 folder = new FolderImpl(path, metadata, handlerFactory, this);
192 }
193 catch (DocumentNotFoundException e)
194 {
195
196 folder = new FolderImpl(path, handlerFactory, this);
197 }
198
199
200 if (!path.equals(Folder.PATH_SEPARATOR))
201 {
202 String parentPath = path;
203 int parentSeparatorIndex = parentPath.lastIndexOf(Folder.PATH_SEPARATOR_CHAR);
204 if (parentSeparatorIndex > 0)
205 {
206 parentPath = parentPath.substring(0, parentSeparatorIndex);
207 }
208 else
209 {
210 parentPath = Folder.PATH_SEPARATOR;
211 }
212 folder.setParent(getFolder(parentPath));
213 }
214
215
216 ((FolderImpl) folder).unmarshalled();
217
218
219 if (fromCache)
220 {
221 addToCache(path, folder);
222 }
223 }
224
225 return folder;
226 }
227
228 /***
229 * <p>
230 * updateFolder
231 * </p>
232 *
233 * @see org.apache.jetspeed.page.document.FolderHandler#updateFolder(org.apache.jetspeed.om.folder.Folder)
234 * @param folder
235 * @throws FailedToUpdateFolderException
236 */
237 public void updateFolder(Folder folder) throws FailedToUpdateFolderException
238 {
239
240 if (folder == null)
241 {
242 log.warn("Recieved null Folder to update");
243 return;
244 }
245 String path = folder.getPath();
246 if (path == null)
247 {
248 path = folder.getId();
249 if (path == null)
250 {
251 log.warn("Recieved Folder with null path/id to update");
252 return;
253 }
254 folder.setPath(path);
255 }
256
257
258 FolderImpl folderImpl = (FolderImpl)folder;
259 folderImpl.setFolderHandler(this);
260 folderImpl.setHandlerFactory(handlerFactory);
261 folderImpl.setPermissionsEnabled(handlerFactory.getPermissionsEnabled());
262 folderImpl.setConstraintsEnabled(handlerFactory.getConstraintsEnabled());
263 folderImpl.marshalling();
264
265
266 File folderFile = new File(documentRootDir, path);
267 if ((folderFile.exists() && !folderFile.isDirectory()) || (!folderFile.exists() && !folderFile.mkdir()))
268 {
269 throw new FailedToUpdateFolderException(folderFile.getAbsolutePath()+" does not exist and cannot be created.");
270 }
271
272
273 try
274 {
275 FolderMetaDataImpl metadata = folderImpl.getFolderMetaData();
276 metadata.setPath(path + Folder.PATH_SEPARATOR + FolderMetaDataImpl.DOCUMENT_TYPE);
277 metadataDocHandler.updateDocument(metadata);
278 }
279 catch (Exception e)
280 {
281 throw new FailedToUpdateFolderException(folderFile.getAbsolutePath()+" failed to update folder.metadata", e);
282 }
283
284
285 addToCache(path, folder);
286 }
287
288 /***
289 * <p>
290 * removeFolder
291 * </p>
292 *
293 * @see org.apache.jetspeed.page.document.FolderHandler#removeFolder(org.apache.jetspeed.om.folder.Folder)
294 * @param folder
295 * @throws FailedToDeleteFolderException
296 */
297 public void removeFolder(Folder folder) throws FailedToDeleteFolderException
298 {
299
300 if (folder == null)
301 {
302 log.warn("Recieved null Folder to remove");
303 return;
304 }
305 String path = folder.getPath();
306 if (path == null)
307 {
308 path = folder.getId();
309 if (path == null)
310 {
311 log.warn("Recieved Folder with null path/id to remove");
312 return;
313 }
314 folder.setPath(path);
315 }
316
317
318 FolderImpl folderImpl = (FolderImpl)folder;
319 try
320 {
321
322 List removeNodes = new ArrayList();
323 Iterator copyIter = folderImpl.getAllNodes().iterator();
324 while (copyIter.hasNext())
325 {
326 removeNodes.add(copyIter.next());
327 }
328
329
330 Iterator removeIter = removeNodes.iterator();
331 while (removeIter.hasNext())
332 {
333 Node node = (Node)removeIter.next();
334 if (node instanceof Folder)
335 {
336
337 removeFolder((Folder)node);
338 }
339 else if (node instanceof Document)
340 {
341
342 try
343 {
344 handlerFactory.getDocumentHandler(node.getType()).removeDocument((Document)node);
345 }
346 catch (Exception e)
347 {
348 File documentFile = new File(this.documentRootDir, node.getPath());
349 throw new FailedToDeleteFolderException(documentFile.getAbsolutePath()+" document cannot be deleted.");
350 }
351 }
352 ((NodeSetImpl)folderImpl.getAllNodes()).remove(node);
353 }
354 }
355 catch (FailedToDeleteFolderException fdfe)
356 {
357 throw fdfe;
358 }
359 catch (Exception e)
360 {
361 throw new FailedToDeleteFolderException(e.getMessage());
362 }
363
364
365 File folderFile = new File(this.documentRootDir, path);
366 File metadataFile = null;
367 if ((folderImpl.getFolderMetaData() != null) && (folderImpl.getFolderMetaData().getPath() != null))
368 {
369 metadataFile = new File(this.documentRootDir, folderImpl.getFolderMetaData().getPath());
370 }
371 if (folderFile.exists() && folderFile.isDirectory())
372 {
373
374 String[] contents = folderFile.list();
375 for (int i = 0; (i < contents.length); i++)
376 {
377 File contentFile = new File(folderFile, contents[i]);
378 if ((metadataFile == null) || !contentFile.equals(metadataFile))
379 {
380 if (!deleteFile(contentFile))
381 {
382 throw new FailedToDeleteFolderException(folderFile.getAbsolutePath()+" unrecognized folder contents cannot be deleted.");
383 }
384 }
385 }
386
387 if ((metadataFile != null) && metadataFile.exists() && !metadataFile.delete())
388 {
389 throw new FailedToDeleteFolderException(folderFile.getAbsolutePath()+" folder metadata cannot be deleted.");
390 }
391
392
393
394 if (!path.equals(Folder.PATH_SEPARATOR) && !folderFile.delete())
395 {
396 throw new FailedToDeleteFolderException(folderFile.getAbsolutePath()+" folder cannot be deleted.");
397 }
398 }
399 else
400 {
401 throw new FailedToDeleteFolderException(folderFile.getAbsolutePath()+" not found.");
402 }
403
404
405 fileCache.remove(path);
406
407
408 if (folderImpl.getFolderMetaData() != null)
409 {
410 folderImpl.getFolderMetaData().setParent(null);
411 }
412 folderImpl.setParent(null);
413 folderImpl.reset();
414 }
415
416 private static final boolean deleteFile(File file)
417 {
418 if (file.isDirectory())
419 {
420 String[] children = file.list();
421 for (int i = 0; (i < children.length); i++)
422 {
423 if (!deleteFile(new File(file, children[i])))
424 {
425 return false;
426 }
427 }
428 }
429 return file.delete();
430 }
431
432 /***
433 * <p>
434 * getFolders
435 * </p>
436 *
437 * @see org.apache.jetspeed.page.document.FolderHandler#getFolders(java.lang.String)
438 * @param path
439 * @return @throws
440 * FolderNotFoundException
441 * @throws FolderNotFoundException
442 * @throws InvalidFolderException
443 * @throws NodeException
444 */
445 public NodeSet getFolders( String path ) throws FolderNotFoundException, InvalidFolderException, NodeException
446 {
447 File parent = new File(documentRootDir, path);
448 if (!parent.exists())
449 {
450 throw new FolderNotFoundException("No folder exists at the path: " + parent.getAbsolutePath());
451 }
452 else
453 {
454 String[] children = getChildrenNames(path, FOLDER_FILTER);
455 NodeSetImpl folders = new NodeSetImpl(path);
456 for (int i = 0; i < children.length; i++)
457 {
458 if (path.endsWith(Folder.PATH_SEPARATOR))
459 {
460 folders.add(getFolder(path + children[i]));
461 }
462 else
463 {
464 folders.add(getFolder(path + Folder.PATH_SEPARATOR + children[i]));
465 }
466 }
467 return folders;
468 }
469 }
470
471 public class DocumentTypeFilter implements FilenameFilter
472 {
473 private String documentType;
474
475 public DocumentTypeFilter( String documentType )
476 {
477 this.documentType = documentType;
478 }
479
480 /***
481 * <p>
482 * accept
483 * </p>
484 *
485 * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String)
486 * @param dir
487 * @param name
488 * @return
489 */
490 public boolean accept( File dir, String name )
491 {
492 return name.endsWith(documentType);
493 }
494
495 }
496
497 /***
498 * <p>
499 * list
500 * </p>
501 *
502 * @see org.apache.jetspeed.page.document.FolderHandler#list(java.lang.String)
503 * @param documentType
504 * @return @throws
505 * FolderNotFoundException
506 */
507 public String[] list( String folderPath, String documentType ) throws FolderNotFoundException
508 {
509 return getChildrenNames(folderPath, new DocumentTypeFilter(documentType));
510 }
511
512 /***
513 * <p>
514 * listAll
515 * </p>
516 *
517 * @see org.apache.jetspeed.page.document.FolderHandler#listAll(java.lang.String)
518 * @param folderPath
519 * @return @throws
520 * FolderNotFoundException
521 */
522 public String[] listAll( String folderPath ) throws FolderNotFoundException
523 {
524 return getChildrenNames(folderPath, null);
525 }
526
527 protected String[] getChildrenNames( String path, FilenameFilter filter ) throws FolderNotFoundException
528 {
529 File parent = new File(documentRootDir, path);
530 if (!parent.exists())
531 {
532 throw new FolderNotFoundException("No folder exists at the path: " + parent.getAbsolutePath());
533 }
534 else
535 {
536 if (filter != null)
537 {
538 return parent.list(filter);
539 }
540 else
541 {
542 return parent.list();
543 }
544 }
545 }
546
547 /***
548 * <p>
549 * getChildNodes
550 * </p>
551 *
552 * @see org.apache.jetspeed.page.document.FolderHandler#getNodes(java.lang.String,boolean,java.lang.String)
553 * @param path
554 * @param regexp
555 * @param documentType
556 * @return NodeSet
557 * @throws FolderNotFoundException
558 * @throws DocumentException
559 * @throws InvalidFolderException
560 * @throws NodeException
561 */
562 public NodeSet getNodes(String path, boolean regexp, String documentType)
563 throws FolderNotFoundException, InvalidFolderException, NodeException
564 {
565
566 if ((path == null) || ! path.startsWith(Folder.PATH_SEPARATOR))
567 {
568 throw new InvalidFolderException( "Invalid path specified " + path );
569 }
570
571
572
573 Folder folder = getFolder(Folder.PATH_SEPARATOR);
574 NodeSetImpl matched = new NodeSetImpl(null);
575 getNodes(folder,path,regexp,matched);
576
577
578 if (documentType != null)
579 {
580 return matched.subset(documentType);
581 }
582 return matched;
583 }
584
585 private void getNodes(Folder folder, String path, boolean regexp, NodeSet matched)
586 throws FolderNotFoundException, InvalidFolderException, NodeException
587 {
588
589 if (path.equals(Folder.PATH_SEPARATOR))
590 {
591 matched.add(folder);
592 return;
593 }
594
595
596 if (path.startsWith(Folder.PATH_SEPARATOR))
597 {
598 path = path.substring(1);
599 }
600
601
602 int separatorIndex = path.indexOf(Folder.PATH_SEPARATOR);
603 if (separatorIndex != -1)
604 {
605
606 String folderName = path.substring(0,separatorIndex);
607 String folderPath = (folder.getPath().endsWith(Folder.PATH_SEPARATOR) ? folder.getPath() : folder.getPath() + Folder.PATH_SEPARATOR) + folderName;
608 NodeSet matchedFolders = null;
609 if (regexp)
610 {
611
612 matchedFolders = ((FolderImpl)folder).getFolders(false).inclusiveSubset(folderPath);
613 }
614 else
615 {
616
617 Folder matchedFolder = getFolder(folderPath);
618 if (matchedFolder != null)
619 {
620 matchedFolders = new NodeSetImpl(folder.getPath());
621 matchedFolders.add(matchedFolder);
622 }
623 }
624 if ((matchedFolders == null) || (matchedFolders.size() == 0))
625 {
626 throw new FolderNotFoundException("Cannot find folder" + folderName + " in " + folder.getPath());
627 }
628
629
630 path = path.substring(separatorIndex);
631 Iterator matchedFoldersIter = matchedFolders.iterator();
632 while (matchedFoldersIter.hasNext())
633 {
634 Folder matchedFolder = (Folder) matchedFoldersIter.next();
635 getNodes(matchedFolder, path, regexp, matched);
636 }
637 return;
638 }
639
640
641 String nodeName = path;
642 String nodePath = (folder.getPath().endsWith(Folder.PATH_SEPARATOR) ? folder.getPath() : folder.getPath() + Folder.PATH_SEPARATOR) + nodeName;
643 if (regexp)
644 {
645
646 Iterator addIter = ((FolderImpl)folder).getAllNodes().inclusiveSubset(nodePath).iterator();
647 while (addIter.hasNext())
648 {
649 matched.add((Node) addIter.next());
650 }
651 }
652 else
653 {
654
655 Iterator findIter = ((FolderImpl)folder).getAllNodes().iterator();
656 while (findIter.hasNext())
657 {
658 Node addNode = (Node) findIter.next();
659 if (addNode.getPath().equals(nodePath))
660 {
661 matched.add(addNode);
662 break;
663 }
664 }
665 }
666 }
667
668
669 /***
670 * <p>
671 * addToCache
672 * </p>
673 *
674 * @param id
675 * @param objectToCache
676 */
677 protected void addToCache( String id, Object objectToCache )
678 {
679 synchronized (fileCache)
680 {
681
682
683 try
684 {
685 fileCache.put(id, objectToCache, this.documentRootDir);
686
687 }
688 catch (java.io.IOException e)
689 {
690
691 String msg = "Error storing Document in the FileCache: " + e.toString();
692 log.error(msg);
693 IllegalStateException ise = new IllegalStateException(msg);
694 ise.initCause(e);
695 }
696 }
697 }
698
699 /***
700 * <p>
701 * refresh
702 * </p>
703 *
704 * @see org.apache.jetspeed.cache.file.FileCacheEventListener#refresh(org.apache.jetspeed.cache.file.FileCacheEntry)
705 * @param entry
706 * @throws Exception
707 */
708 public void refresh( FileCacheEntry entry ) throws Exception
709 {
710 if (entry.getDocument() instanceof Folder )
711 {
712 Folder folder = (Folder) entry.getDocument();
713 entry.setDocument(getFolder(folder.getPath(), false));
714 if (((AbstractNode)folder).getParent(false) != null)
715 {
716 FileCacheEntry parentEntry = fileCache.get(((AbstractNode)folder).getParent(false).getPath());
717 refresh(parentEntry);
718 }
719 }
720 else if(entry.getDocument() instanceof Document)
721 {
722 Document doc = (Document) entry.getDocument();
723 if (doc.getType().equals(FolderMetaDataImpl.DOCUMENT_TYPE))
724 {
725 FileCacheEntry folderEntry = fileCache.get(((AbstractNode)doc).getParent().getPath());
726 refresh(folderEntry);
727 }
728 }
729
730 if(entry.getDocument() instanceof Reset)
731 {
732 ((Reset)entry.getDocument()).reset();
733 }
734
735 }
736
737 /***
738 * <p>
739 * evict
740 * </p>
741 *
742 * @see org.apache.jetspeed.cache.file.FileCacheEventListener#evict(org.apache.jetspeed.cache.file.FileCacheEntry)
743 * @param entry
744 * @throws Exception
745 */
746 public void evict( FileCacheEntry entry ) throws Exception
747 {
748
749 }
750
751 public boolean isFolder(String path)
752 {
753 return new File(this.documentRootDir, path).isDirectory();
754 }
755 }