KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > versioning > FilesystemInterceptor


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.modules.versioning;
20
21 import org.openide.filesystems.*;
22 import org.netbeans.modules.masterfs.providers.ProvidedExtensions;
23 import org.netbeans.modules.versioning.spi.VCSInterceptor;
24 import org.netbeans.modules.versioning.spi.VersioningSystem;
25 import java.io.File JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.util.*;
28
29 /**
30  * Plugs into IDE filesystem and delegates file operations to registered versioning systems.
31  *
32  * @author Maros Sandor
33  */

34 class FilesystemInterceptor extends ProvidedExtensions implements FileChangeListener {
35     
36     private VersioningManager master;
37
38     // === LIFECYCLE =======================================================================================
39

40     /**
41      * Initializes the interceptor by registering it into master filesystem.
42      * Registers listeners to all disk filesystems.
43      * @param versioningManager
44      */

45     void init(VersioningManager versioningManager) {
46         assert master == null;
47         master = versioningManager;
48         Set filesystems = getRootFilesystems();
49         for (Iterator i = filesystems.iterator(); i.hasNext();) {
50             FileSystem fileSystem = (FileSystem) i.next();
51             fileSystem.addFileChangeListener(this);
52         }
53     }
54
55     /**
56      * Unregisters listeners from all disk filesystems.
57      */

58     void shutdown() {
59         Set filesystems = getRootFilesystems();
60         for (Iterator i = filesystems.iterator(); i.hasNext();) {
61             FileSystem fileSystem = (FileSystem) i.next();
62             fileSystem.removeFileChangeListener(this);
63         }
64     }
65
66     /**
67      * Retrieves all filesystems.
68      *
69      * @return Set<FileSystem> set of filesystems
70      */

71     private Set<FileSystem> getRootFilesystems() {
72         Set<FileSystem> filesystems = new HashSet<FileSystem>();
73         File JavaDoc [] roots = File.listRoots();
74         for (int i = 0; i < roots.length; i++) {
75             File JavaDoc root = roots[i];
76             FileObject fo = FileUtil.toFileObject(FileUtil.normalizeFile(root));
77             if (fo == null) continue;
78             try {
79                 filesystems.add(fo.getFileSystem());
80             } catch (FileStateInvalidException e) {
81                 // ignore invalid filesystems
82
}
83         }
84         return filesystems;
85     }
86
87     // ==================================================================================================
88
// CHANGE
89
// ==================================================================================================
90

91     public void fileChanged(FileEvent fe) {
92         removeFromDeletedFiles(fe.getFile());
93         getInterceptor(fe).afterChange();
94     }
95             
96     public void beforeChange(FileObject fo) {
97         getInterceptor(FileUtil.toFile(fo), fo.isFolder()).beforeChange();
98     }
99
100     // ==================================================================================================
101
// DELETE
102
// ==================================================================================================
103

104     private void removeFromDeletedFiles(File JavaDoc file) {
105         synchronized(deletedFiles) {
106             deletedFiles.remove(file);
107         }
108     }
109
110     private void removeFromDeletedFiles(FileObject fo) {
111         synchronized(deletedFiles) {
112             if (deletedFiles.size() > 0) {
113                 deletedFiles.remove(FileUtil.toFile(fo));
114             }
115         }
116     }
117     
118     public DeleteHandler getDeleteHandler(File JavaDoc file) {
119         removeFromDeletedFiles(file);
120         DelegatingInterceptor dic = getInterceptor(file, false);
121         return dic.beforeDelete() ? dic : null;
122     }
123
124     public void fileDeleted(FileEvent fe) {
125         removeFromDeletedFiles(fe.getFile());
126         getInterceptor(fe).afterDelete();
127     }
128         
129     // ==================================================================================================
130
// CREATE
131
// ==================================================================================================
132

133     public void beforeCreate(FileObject parent, String JavaDoc name, boolean isFolder) {
134         File JavaDoc file = FileUtil.toFile(parent);
135         if (file == null) return;
136         file = new File JavaDoc(file, name);
137         DelegatingInterceptor dic = getInterceptor(file, isFolder);
138         dic.beforeCreate();
139     }
140
141     public void fileFolderCreated(FileEvent fe) {
142         removeFromDeletedFiles(fe.getFile());
143         getInterceptor(fe).afterCreate();
144     }
145
146     public void fileDataCreated(FileEvent fe) {
147         removeFromDeletedFiles(fe.getFile());
148         getInterceptor(fe).afterCreate();
149     }
150     
151     // ==================================================================================================
152
// MOVE
153
// ==================================================================================================
154

155     public IOHandler getMoveHandler(File JavaDoc from, File JavaDoc to) {
156         DelegatingInterceptor dic = getInterceptor(from, to);
157         return dic.beforeMove() ? dic : null;
158     }
159         
160     public IOHandler getRenameHandler(File JavaDoc from, String JavaDoc newName) {
161         File JavaDoc to = new File JavaDoc(from.getParentFile(), newName);
162         return getMoveHandler(from, to);
163     }
164
165     public void fileRenamed(FileRenameEvent fe) {
166         removeFromDeletedFiles(fe.getFile());
167         getInterceptor(fe).afterMove();
168     }
169     
170     public void fileAttributeChanged(FileAttributeEvent fe) {
171         // not interested
172
}
173
174     private DelegatingInterceptor getInterceptor(FileEvent fe) {
175         FileObject fo = fe.getFile();
176         if (fo == null) return nullDelegatingInterceptor;
177         File JavaDoc file = FileUtil.toFile(fo);
178         if (file == null) return nullDelegatingInterceptor;
179
180         VersioningSystem lh = master.getLocalHistory(file);
181         VersioningSystem vs = master.getOwner(file);
182
183         VCSInterceptor vsInterceptor = vs != null ? vs.getVCSInterceptor() : null;
184         VCSInterceptor lhInterceptor = lh != null ? lh.getVCSInterceptor() : null;
185         
186         if (vsInterceptor == null && lhInterceptor == null) return nullDelegatingInterceptor;
187
188         if (fe instanceof FileRenameEvent) {
189             FileRenameEvent fre = (FileRenameEvent) fe;
190             File JavaDoc parent = file.getParentFile();
191             if (parent != null) {
192                 String JavaDoc name = fre.getName();
193                 String JavaDoc ext = fre.getExt();
194                 if (ext != null && ext.length() > 0) { // NOI18N
195
name += "." + ext; // NOI18N
196
}
197                 File JavaDoc from = new File JavaDoc(parent, name);
198                 return new DelegatingInterceptor(vsInterceptor, lhInterceptor, from, file, false);
199             }
200             return nullDelegatingInterceptor;
201         } else {
202             return new DelegatingInterceptor(vsInterceptor, lhInterceptor, file, null, false);
203         }
204     }
205
206     private DelegatingInterceptor getInterceptor(File JavaDoc file, boolean isDirectory) {
207         if (file == null) return nullDelegatingInterceptor;
208         
209         VersioningSystem vs = master.getOwner(file);
210         VCSInterceptor vsInterceptor = vs != null ? vs.getVCSInterceptor() : nullVCSInterceptor;
211
212         VersioningSystem lhvs = master.getLocalHistory(file);
213         VCSInterceptor localHistoryInterceptor = lhvs != null ? lhvs.getVCSInterceptor() : nullVCSInterceptor;
214         
215         return new DelegatingInterceptor(vsInterceptor, localHistoryInterceptor, file, null, isDirectory);
216     }
217
218     private DelegatingInterceptor getInterceptor(File JavaDoc from, File JavaDoc to) {
219         if (from == null || to == null) return nullDelegatingInterceptor;
220         
221         VersioningSystem vs = master.getOwner(from);
222         VCSInterceptor vsInterceptor = vs != null ? vs.getVCSInterceptor() : nullVCSInterceptor;
223
224         VersioningSystem lhvs = master.getLocalHistory(from);
225         VCSInterceptor localHistoryInterceptor = lhvs != null ? lhvs.getVCSInterceptor() : nullVCSInterceptor;
226         
227         return new DelegatingInterceptor(vsInterceptor, localHistoryInterceptor, from, to, false);
228     }
229     
230     private final DelegatingInterceptor nullDelegatingInterceptor = new DelegatingInterceptor() {
231         public boolean beforeDelete() { return false; }
232         public void doDelete() throws IOException JavaDoc { }
233         public void afterDelete() { }
234         public boolean beforeMove() { return false; }
235         public void doMove() throws IOException JavaDoc { }
236         public boolean beforeCreate() { return false; }
237         public void doCreate() throws IOException JavaDoc { }
238         public void afterCreate() { }
239         public void beforeChange() { }
240         public void afterChange() { }
241         public void afterMove() { }
242         public void handle() throws IOException JavaDoc { }
243         public boolean delete(File JavaDoc file) { throw new UnsupportedOperationException JavaDoc(); }
244     };
245     
246     private final VCSInterceptor nullVCSInterceptor = new VCSInterceptor() {};
247     
248     /**
249      * Delete interceptor: holds files and folders that we do not want to delete but must pretend that they were deleted.
250      */

251     private final Set<File JavaDoc> deletedFiles = new HashSet<File JavaDoc>(5);
252     
253     private class DelegatingInterceptor implements IOHandler, DeleteHandler {
254         
255         final VCSInterceptor interceptor;
256         final VCSInterceptor lhInterceptor;
257         final File JavaDoc file;
258         final File JavaDoc to;
259         private final boolean isDirectory;
260
261         private DelegatingInterceptor() {
262             this(null, null, null, null, false);
263         }
264         
265         public DelegatingInterceptor(VCSInterceptor interceptor, VCSInterceptor lhInterceptor, File JavaDoc file, File JavaDoc to, boolean isDirectory) {
266             this.interceptor = interceptor != null ? interceptor : nullVCSInterceptor;
267             this.lhInterceptor = lhInterceptor != null ? lhInterceptor : nullVCSInterceptor;
268             this.file = file;
269             this.to = to;
270             this.isDirectory = isDirectory;
271         }
272
273         public boolean beforeDelete() {
274             lhInterceptor.beforeDelete(file);
275             return interceptor.beforeDelete(file);
276         }
277
278         public void doDelete() throws IOException JavaDoc {
279             lhInterceptor.doDelete(file);
280             interceptor.doDelete(file);
281         }
282
283         public void afterDelete() {
284             lhInterceptor.afterDelete(file);
285             interceptor.afterDelete(file);
286         }
287
288         public boolean beforeMove() {
289             lhInterceptor.beforeMove(file, to);
290             return interceptor.beforeMove(file, to);
291         }
292
293         public void doMove() throws IOException JavaDoc {
294             lhInterceptor.doMove(file, to);
295             interceptor.doMove(file, to);
296         }
297
298         public void afterMove() {
299             lhInterceptor.afterMove(file, to);
300             interceptor.afterMove(file, to);
301         }
302
303         public boolean beforeCreate() {
304             lhInterceptor.beforeCreate(file, isDirectory);
305             return interceptor.beforeCreate(file, isDirectory);
306         }
307
308         public void doCreate() throws IOException JavaDoc {
309             lhInterceptor.doCreate(file, isDirectory);
310             interceptor.doCreate(file, isDirectory);
311         }
312
313         public void afterCreate() {
314             lhInterceptor.afterCreate(file);
315             interceptor.afterCreate(file);
316         }
317
318         public void afterChange() {
319             lhInterceptor.afterChange(file);
320             interceptor.afterChange(file);
321         }
322
323         public void beforeChange() {
324             lhInterceptor.beforeChange(file);
325             interceptor.beforeChange(file);
326         }
327         
328         /**
329          * We are doing MOVE here, inspite of the generic name of the method.
330          *
331          * @throws IOException
332          */

333         public void handle() throws IOException JavaDoc {
334             lhInterceptor.doMove(file, to);
335             interceptor.doMove(file, to);
336         }
337
338         /**
339          * This must act EXACTLY like java.io.File.delete(). This means:
340
341          * 1.1 if the file is a file and was deleted, return true
342          * 1.2 if the file is a file and was NOT deleted because we want to keep it (is part of versioning metadata), also return true
343          * this is done this way to enable bottom-up recursive file deletion
344          * 1.3 if the file is a file that should be deleted but the operation failed (the file is locked, for example), return false
345          *
346          * 2.1 if the file is an empty directory that was deleted, return true
347          * 2.2 if the file is a NON-empty directory that was NOT deleted because it contains files that were NOT deleted in step 1.2, return true
348          * 2.3 if the file is a NON-empty directory that was NOT deleted because it contains some files that were not previously deleted, return false
349          *
350          * @param file file or folder to delete
351          * @return true if the file was successfully deleted (event virtually deleted), false otherwise
352          */

353         public boolean delete(File JavaDoc file) {
354             File JavaDoc [] children = file.listFiles();
355             if (children != null) {
356                 synchronized(deletedFiles) {
357                     for (File JavaDoc child : children) {
358                         if (!deletedFiles.contains(child)) return false;
359                     }
360                 }
361             }
362             try {
363                 lhInterceptor.doDelete(file);
364                 interceptor.doDelete(file);
365                 synchronized(deletedFiles) {
366                     if (file.isDirectory()) {
367                         // the directory was virtually deleted, we can forget about its children
368
for (Iterator<File JavaDoc> i = deletedFiles.iterator(); i.hasNext(); ) {
369                             File JavaDoc fakedFile = i.next();
370                             if (file.equals(fakedFile.getParentFile())) {
371                                 i.remove();
372                             }
373                         }
374                     }
375                     if (file.exists()) {
376                         deletedFiles.add(file);
377                     } else {
378                         deletedFiles.remove(file);
379                     }
380                 }
381                 return true;
382             } catch (IOException JavaDoc e) {
383                 // the interceptor failed to delete the file
384
return false;
385             }
386         }
387         
388 // VCSInterceptor getInterceptor() {
389
// return interceptor;
390
// }
391
}
392 }
393
Popular Tags