Coverage Report - org.webslinger.commons.vfs.LayeredFileSystem
 
Classes in this File Line Coverage Branch Coverage Complexity
LayeredFileSystem
19%
6/32
25%
1/4
0
LayeredFileSystem$LayeredFileListener
0%
0/56
0%
0/13
0
 
 1  
 package org.webslinger.commons.vfs;
 2  
 
 3  
 import java.util.HashSet;
 4  
 import java.util.Set;
 5  
 import java.util.SortedMap;
 6  
 import java.util.concurrent.ConcurrentMap;
 7  
 import java.util.concurrent.atomic.AtomicReference;
 8  
 
 9  
 import org.apache.commons.vfs.FileChangeEvent;
 10  
 import org.apache.commons.vfs.FileListener;
 11  
 import org.apache.commons.vfs.FileName;
 12  
 import org.apache.commons.vfs.FileObject;
 13  
 import org.apache.commons.vfs.FileSystem;
 14  
 import org.apache.commons.vfs.FileSystemException;
 15  
 import org.apache.commons.vfs.FileSystemOptions;
 16  
 import org.apache.commons.vfs.events.AbstractFileChangeEvent;
 17  
 import org.apache.commons.vfs.events.ChangedEvent;
 18  
 import org.apache.commons.vfs.events.CreateEvent;
 19  
 import org.apache.commons.vfs.events.DeleteEvent;
 20  
 
 21  
 import org.webslinger.lang.ConcurrentUtil;
 22  
 
 23  0
 public abstract class LayeredFileSystem<N extends FileName, F extends LayeredFileObject<N, F, S>, S extends LayeredFileSystem<N, F, S>> extends AbstractGenerifiedFileSystem<N, F, S> {
 24  92
     protected final SortedMap<String, LayeredFileListener> listeners = ConcurrentUtil.createSortedMap();
 25  
 
 26  
     public LayeredFileSystem(N name, FileObject root, FileSystemOptions options) throws FileSystemException {
 27  92
         super(name, root, options);
 28  92
     }
 29  
 
 30  
     protected abstract F[] newArray(int length);
 31  
 
 32  
     public void addListener(F file, FileListener listener) {
 33  
         //System.err.println("addListener(" + file + ", " + listener + ")");
 34  
         try {
 35  0
             LayeredFileListener chain = listeners.get(file.getName().getPath());
 36  0
             if (chain == null) {
 37  0
                 chain = new LayeredFileListener(file);
 38  0
                 listeners.put(file.getName().getPath(), chain);
 39  
             }
 40  0
             chain.addListener(listener);
 41  0
         } catch (FileSystemException e) {
 42  0
             throw (InternalError) new InternalError(e.getMessage()).initCause(e);
 43  0
         }
 44  0
     }
 45  
 
 46  
     public void removeListener(F file, FileListener listener) {
 47  
         try {
 48  0
             LayeredFileListener chain = listeners.get(file.getName().getPath());
 49  0
             if (chain == null) return;
 50  0
             switch (chain.removeListener(listener)) {
 51  
                 case 0:
 52  0
                     break;
 53  
                 case 1:
 54  0
                     listeners.remove(file.getName().getPath());
 55  0
                     break;
 56  
                 case 2:
 57  
             }
 58  0
         } catch (FileSystemException e) {
 59  0
             throw (InternalError) new InternalError(e.getMessage()).initCause(e);
 60  0
         }
 61  0
     }
 62  
 
 63  
     protected void updateListeners(FileName name) throws FileSystemException {
 64  384
         String startsWith = name.getPath() + "/";
 65  384
         for (LayeredFileListener chain: listeners.tailMap(startsWith).values()) {
 66  0
             if (!chain.path.startsWith(startsWith)) break;
 67  0
             F nestedFile = resolveFile(chain.path);
 68  0
             FileObject realFile = nestedFile.getFile(false);
 69  0
             chain.checkFileChanged(realFile);
 70  0
         }
 71  384
     }
 72  
 
 73  
     protected abstract FileSet getRealFiles(F file) throws FileSystemException;
 74  
 
 75  
     protected FileSet createFileSet(FileObject[] contentFiles, FileObject[] existantFiles) {
 76  0
         return new FileSet(contentFiles, existantFiles);
 77  
     }
 78  
 
 79  
     protected class LayeredFileListener implements FileListener {
 80  
         protected String path;
 81  0
         protected AtomicReference<FileSet> fileSet = new AtomicReference<FileSet>();;
 82  0
         protected AtomicReference<HashSet<FileListener>> listeners = new AtomicReference<HashSet<FileListener>>(new HashSet<FileListener>());
 83  
 
 84  0
         protected LayeredFileListener(FileObject fo) throws FileSystemException {
 85  0
             path = fo.getName().getPath();
 86  0
             fetchFiles();
 87  0
         }
 88  
 
 89  
         protected void fetchFiles() throws FileSystemException {
 90  0
             fileSet.set(getRealFiles(resolveFile(path)));
 91  0
         }
 92  
 
 93  
         protected void addAllListeners() throws FileSystemException {
 94  0
             FileSet fileSet = this.fileSet.get();
 95  0
             addAllListenersSet(fileSet.contentFiles);
 96  0
             addAllListenersSet(fileSet.existantFiles);
 97  0
         }
 98  
 
 99  
         protected void addAllListenersSet(Set<FileSystemAndNameKey> set) throws FileSystemException {
 100  0
             for (FileSystemAndNameKey key: set) {
 101  0
                 key.getFileSystem().addListener(key.getFileSystem().resolveFile(key.getName()), this);
 102  
             }
 103  0
         }
 104  
 
 105  
         protected void removeAllListeners() throws FileSystemException {
 106  0
             FileSet fileSet = this.fileSet.get();
 107  0
             removeAllListenersSet(fileSet.contentFiles);
 108  0
             removeAllListenersSet(fileSet.existantFiles);
 109  0
         }
 110  
 
 111  
         protected void removeAllListenersSet(Set<FileSystemAndNameKey> set) throws FileSystemException {
 112  0
             for (FileSystemAndNameKey key: set) {
 113  0
                 key.getFileSystem().removeListener(key.getFileSystem().resolveFile(key.getName()), this);
 114  
             }
 115  0
         }
 116  
 
 117  
         protected void checkFileChanged(FileObject newFile) throws FileSystemException {
 118  0
             if (!listeners.get().isEmpty()) {
 119  0
                 removeAllListeners();
 120  0
                 fetchFiles();
 121  0
                 addAllListeners();
 122  
             }
 123  0
         }
 124  
 
 125  
         protected FileObject getFile() throws Exception {
 126  0
             return resolveFile(path);
 127  
         }
 128  
 
 129  
         // no need for locking, protected by the global lock on VirtualFileSystem.listeners
 130  
         protected boolean addListener(FileListener listener) throws FileSystemException {
 131  
             HashSet<FileListener> oldListeners, newListeners;
 132  
             do {
 133  0
                 oldListeners = listeners.get();
 134  0
                 if (oldListeners.contains(listener)) return false;
 135  0
                 newListeners = new HashSet<FileListener>(oldListeners);
 136  0
                 newListeners.add(listener);
 137  0
             } while (!listeners.compareAndSet(oldListeners, newListeners));
 138  0
             if (newListeners.size() == 1) addAllListeners();
 139  0
             return true;
 140  
         }
 141  
 
 142  
         protected int removeListener(FileListener listener) throws FileSystemException {
 143  
             HashSet<FileListener> oldListeners, newListeners;
 144  
             do {
 145  0
                 oldListeners = listeners.get();
 146  0
                 if (!oldListeners.contains(listener)) return 0;
 147  0
                 newListeners = new HashSet<FileListener>(oldListeners);
 148  0
                 newListeners.remove(listener);
 149  0
             } while (!listeners.compareAndSet(oldListeners, newListeners));
 150  0
             if (newListeners.size() == 0) {
 151  0
                 removeAllListeners();
 152  0
                 return 1;
 153  
             }
 154  0
             return 2;
 155  
         }
 156  
 
 157  
         public void fileChanged(FileChangeEvent event) throws Exception {
 158  0
             if (!fileSet.get().contentFiles.contains(event.getFile())) return;
 159  0
             fireEvent(new ChangedEvent(getFile()));
 160  0
         }
 161  
 
 162  
         public void fileCreated(FileChangeEvent event) throws Exception {
 163  0
             if (!fileSet.get().existantFiles.contains(event.getFile())) return;
 164  0
             fireEvent(new CreateEvent(getFile()));
 165  0
         }
 166  
 
 167  
         public void fileDeleted(FileChangeEvent event) throws Exception {
 168  0
             if (!fileSet.get().existantFiles.contains(event.getFile())) return;
 169  0
             fireEvent(new DeleteEvent(getFile()));
 170  0
         }
 171  
 
 172  
         protected void fireEvent(AbstractFileChangeEvent event) throws Exception {
 173  0
             for (FileListener listener: listeners.get()) {
 174  0
                 event.notify(listener);
 175  
             }
 176  0
         }
 177  
     }
 178  
 }
 179