KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > subversion > FilesystemHandler


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-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.subversion;
21
22 import javax.swing.SwingUtilities JavaDoc;
23 import org.netbeans.modules.subversion.util.FileUtils;
24 import org.netbeans.modules.subversion.util.SvnUtils;
25 import org.netbeans.modules.subversion.client.SvnClient;
26 import org.openide.ErrorManager;
27
28 import java.io.File JavaDoc;
29 import java.io.IOException JavaDoc;
30 import java.util.*;
31 import java.util.logging.Logger JavaDoc;
32 import java.util.logging.Level JavaDoc;
33
34 import org.netbeans.modules.versioning.spi.VCSInterceptor;
35 import org.netbeans.modules.versioning.util.Utils;
36 import org.tigris.subversion.svnclientadapter.*;
37
38 /**
39  * Handles events fired from the filesystem such as file/folder create/delete/move.
40  *
41  * @author Maros Sandor
42  */

43 class FilesystemHandler extends VCSInterceptor {
44         
45     private final Subversion svn;
46     private final FileStatusCache cache;
47     
48     /**
49      * Stores .svn folders that should be deleted ASAP.
50      */

51     private final Set<File JavaDoc> invalidMetadata = new HashSet<File JavaDoc>(5);
52     
53     public FilesystemHandler(Subversion svn) {
54         this.svn = svn;
55         cache = svn.getStatusCache();
56     }
57
58     public boolean beforeDelete(File JavaDoc file) {
59         if (SvnUtils.isPartOfSubversionMetadata(file)) return true;
60         // calling cache results in SOE, we must check manually
61
return !file.isFile() && hasMetadata(file);
62     }
63
64     /**
65      * This interceptor ensures that subversion metadata is NOT deleted.
66      *
67      * @param file file to delete
68      */

69     public void doDelete(File JavaDoc file) throws IOException JavaDoc {
70         boolean isMetadata = SvnUtils.isPartOfSubversionMetadata(file);
71         if (!isMetadata) {
72             remove(file);
73         }
74     }
75
76     public void afterDelete(final File JavaDoc file) {
77         Utils.post(new Runnable JavaDoc() {
78             public void run() {
79                 fileDeletedImpl(file);
80             }
81         });
82     }
83
84     public boolean beforeMove(File JavaDoc from, File JavaDoc to) {
85         File JavaDoc destDir = to.getParentFile();
86         if (from != null && destDir != null) {
87             FileInformation info = cache.getStatus(from);
88             if ((info.getStatus() & FileInformation.STATUS_VERSIONED) != 0) {
89                 return Subversion.getInstance().isManaged(to);
90             }
91             // else XXX handle file with saved administative
92
// right now they have old status in cache but is it guaranteed?
93
}
94
95         return false;
96     }
97
98     public void doMove(final File JavaDoc from, final File JavaDoc to) throws IOException JavaDoc {
99         if (SwingUtilities.isEventDispatchThread()) {
100             
101             Logger.getLogger("org.netbeans.modules.subversion").log(Level.INFO, "Warning: launching external process in AWT", new Exception JavaDoc().fillInStackTrace());
102             final Throwable JavaDoc innerT[] = new Throwable JavaDoc[1];
103             Runnable JavaDoc outOfAwt = new Runnable JavaDoc() {
104                 public void run() {
105                     try {
106                         svnMoveImplementation(from, to);
107                     } catch (Throwable JavaDoc t) {
108                         innerT[0] = t;
109                     }
110                 }
111             };
112             
113             Subversion.getInstance().getRequestProcessor().post(outOfAwt).waitFinished();
114             if (innerT[0] != null) {
115                 if (innerT[0] instanceof IOException JavaDoc) {
116                     throw (IOException JavaDoc) innerT[0];
117                 } else if (innerT[0] instanceof RuntimeException JavaDoc) {
118                     throw (RuntimeException JavaDoc) innerT[0];
119                 } else if (innerT[0] instanceof Error JavaDoc) {
120                     throw (Error JavaDoc) innerT[0];
121                 } else {
122                     throw new IllegalStateException JavaDoc("Unexpected exception class: " + innerT[0]); // NOI18N
123
}
124             }
125             
126             // end of hack
127

128         } else {
129             svnMoveImplementation(from, to);
130         }
131     }
132
133     public void afterMove(final File JavaDoc from, final File JavaDoc to) {
134         Utils.post(new Runnable JavaDoc() {
135             public void run() {
136                 cache.refresh(to, FileStatusCache.REPOSITORY_STATUS_UNKNOWN);
137                 File JavaDoc parent = to.getParentFile();
138                 if (parent != null) {
139                     if (from.equals(to)) {
140                         ErrorManager.getDefault().log(ErrorManager.WARNING, "Wrong (identity) rename event for " + from.getAbsolutePath()); // NOI18N
141
}
142                     cache.refresh(from, FileStatusCache.REPOSITORY_STATUS_UNKNOWN);
143                 }
144             }
145         });
146     }
147     
148     public boolean beforeCreate(File JavaDoc file, boolean isDirectory) {
149         if (svn.isAdministrative(file.getName())) {
150             if (file.isDirectory()) {
151                 File JavaDoc f = new File JavaDoc(file, Subversion.INVALID_METADATA_MARKER);
152                 try {
153                     f.createNewFile();
154                 } catch (IOException JavaDoc e) {
155                     ErrorManager.getDefault().log(ErrorManager.ERROR, "Unable to create marker: " + f.getAbsolutePath()); // NOI18N
156
}
157                 invalidMetadata.add(file);
158             }
159             return true;
160         } else {
161             if (!file.exists()) {
162                 int status = cache.getStatus(file).getStatus();
163                 if (status == FileInformation.STATUS_VERSIONED_REMOVEDLOCALLY) {
164                     try {
165                         SvnClient client = Subversion.getInstance().getClient(true);
166                         client.revert(file, false);
167                         file.delete();
168                     } catch (SVNClientException ex) {
169                         ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
170                     }
171                 }
172             }
173             return false;
174         }
175     }
176
177     public void doCreate(File JavaDoc file, boolean isDirectory) throws IOException JavaDoc {
178     }
179
180     public void afterCreate(final File JavaDoc file) {
181         Utils.post(new Runnable JavaDoc() {
182             public void run() {
183                 if (file == null) return;
184                 int status = cache.refresh(file, FileStatusCache.REPOSITORY_STATUS_UNKNOWN).getStatus();
185
186                 if ((status & FileInformation.STATUS_MANAGED) == 0) return;
187
188 // if (properties_changed) cache.directoryContentChanged(file.getParentFile());
189
if (file.isDirectory()) cache.directoryContentChanged(file);
190             }
191         });
192     }
193     
194     public void afterChange(final File JavaDoc file) {
195         Utils.post(new Runnable JavaDoc() {
196             public void run() {
197                 if ((cache.getStatus(file).getStatus() & FileInformation.STATUS_MANAGED) != 0) {
198                     cache.refreshCached(file, FileStatusCache.REPOSITORY_STATUS_UNKNOWN);
199                 }
200             }
201         });
202     }
203
204     /**
205      * Removes invalid metadata from all known folders.
206      */

207     void removeInvalidMetadata() {
208         synchronized(invalidMetadata) {
209             for (File JavaDoc file : invalidMetadata) {
210                 Utils.deleteRecursively(file);
211             }
212             invalidMetadata.clear();
213         }
214     }
215     
216     // private methods ---------------------------
217

218     /**
219      * If a regular file is deleted then update its Entries as if it has been removed.
220      *
221      * @param file deleted file
222      */

223     private void fileDeletedImpl(File JavaDoc file) {
224         if (file == null) return;
225         int status = cache.getStatus(file).getStatus();
226         if (status != FileInformation.STATUS_NOTVERSIONED_EXCLUDED && status != FileInformation.STATUS_NOTVERSIONED_NEWLOCALLY) {
227             try {
228                 SvnClient client = Subversion.getInstance().getClient(false);
229                 client.remove(new File JavaDoc [] { file }, true);
230     
231             } catch (SVNClientException e) {
232                 // ignore; we do not know what to do here; does no harm, the file was probably Locally New
233
}
234         }
235         // fire event explicitly because the file is already gone
236
// so svnClientAdapter does not fire ISVNNotifyListener event
237
cache.refresh(file, FileStatusCache.REPOSITORY_STATUS_UNKNOWN);
238     }
239     
240     private boolean hasMetadata(File JavaDoc file) {
241         return new File JavaDoc(file, ".svn/entries").canRead() || new File JavaDoc(file, "_svn/entries").canRead();
242     }
243     
244     private boolean remove(File JavaDoc file) {
245         try {
246             SvnClient client = Subversion.getInstance().getClient(false);
247             // funny thing is, the command will delete all files recursively
248
client.remove(new File JavaDoc [] { file }, true);
249             return true;
250         } catch (SVNClientException e) {
251             return false;
252         }
253     }
254
255     public void svnMoveImplementation(final File JavaDoc srcFile, final File JavaDoc dstFile) throws IOException JavaDoc {
256         try {
257             boolean force = true; // file with local changes must be forced
258
SvnClient client = Subversion.getInstance().getClient(false);
259             
260             File JavaDoc tmpMetadata = null;
261             try {
262                 // prepare destination, it must be under Subversion control
263
removeInvalidMetadata();
264
265                 File JavaDoc parent;
266                 if (dstFile.isDirectory()) {
267                     parent = dstFile;
268                 } else {
269                     parent = dstFile.getParentFile();
270                 }
271
272                 if (parent != null) {
273                     int status = cache.getStatus(parent).getStatus();
274                     assert Subversion.getInstance().isManaged(parent); // see implsMove above
275

276                     if ((FileInformation.STATUS_VERSIONED & status) == 0) {
277                         addDirectories(parent);
278                     }
279                 }
280
281                 // perform
282
int retryCounter = 6;
283                 while (true) {
284                     try {
285                         client.move(srcFile, dstFile, force);
286                         break;
287                     } catch (SVNClientException e) {
288                         // svn: Working copy '/tmp/co/svn-prename-19/AnagramGame-pack-rename/src/com/toy/anagrams/ui2' locked
289
if (e.getMessage().endsWith("' locked") && retryCounter > 0) { // NOI18N
290
// XXX HACK AWT- or FS Monitor Thread performs
291
// concurrent operation
292
try {
293                                 Thread.sleep(107);
294                             } catch (InterruptedException JavaDoc ex) {
295                                 // ignore
296
}
297                             retryCounter--;
298                             continue;
299                         }
300
301                         // XXX loosing file history is less harm than raising IOException
302
// that completelly breaks clients (namely refactoring can not handle IOEx)
303
if (srcFile.renameTo(dstFile)) {
304                             ErrorManager.getDefault().annotate(e, "Relaxing Subversion rename error...."); // NOI18N
305
ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); // NOI18N
306
break;
307                         } else {
308                             IOException JavaDoc ex = new IOException JavaDoc("Subversion failed to rename " + srcFile.getAbsolutePath() + " to: " + dstFile.getAbsolutePath()); // NOI18N
309
ex.initCause(e);
310                             throw ex;
311                         }
312                     }
313                 }
314             } finally {
315                 if (tmpMetadata != null) {
316                     FileUtils.deleteRecursively(tmpMetadata);
317                 }
318             }
319         } catch (SVNClientException e) {
320             IOException JavaDoc ex = new IOException JavaDoc("Subversion failed to rename " + srcFile.getAbsolutePath() + " to: " + dstFile.getAbsolutePath()); // NOI18N
321
ex.initCause(e);
322             throw ex;
323         }
324     }
325
326     /**
327      * Seeks versioned root and then adds all folders
328      * under Subversion (so it contains metadata),
329      */

330     private void addDirectories(File JavaDoc dir) throws SVNClientException {
331         File JavaDoc parent = dir.getParentFile();
332         if (parent != null) {
333             int status = cache.getStatus(parent).getStatus();
334             if ((FileInformation.STATUS_VERSIONED & status) == 0) {
335                 addDirectories(parent); // RECURSION
336
}
337             SvnClient client = Subversion.getInstance().getClient(false);
338             client.addDirectory(dir, false);
339             cache.refresh(dir, FileStatusCache.REPOSITORY_STATUS_UNKNOWN);
340         } else {
341             throw new SVNClientException("Reached FS root, but it's still not Subversion versioned!"); // NOI18N
342
}
343     }
344 }
345
Popular Tags