Source Code Cross Referenced for FilesystemHandler.java in  » IDE-Netbeans » subversion » org » netbeans » modules » subversion » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Netbeans » subversion » org.netbeans.modules.subversion 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003:         *
004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005:         *
006:         * The contents of this file are subject to the terms of either the GNU
007:         * General Public License Version 2 only ("GPL") or the Common
008:         * Development and Distribution License("CDDL") (collectively, the
009:         * "License"). You may not use this file except in compliance with the
010:         * License. You can obtain a copy of the License at
011:         * http://www.netbeans.org/cddl-gplv2.html
012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013:         * specific language governing permissions and limitations under the
014:         * License.  When distributing the software, include this License Header
015:         * Notice in each file and include the License file at
016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
017:         * particular file as subject to the "Classpath" exception as provided
018:         * by Sun in the GPL Version 2 section of the License file that
019:         * accompanied this code. If applicable, add the following below the
020:         * License Header, with the fields enclosed by brackets [] replaced by
021:         * your own identifying information:
022:         * "Portions Copyrighted [year] [name of copyright owner]"
023:         *
024:         * Contributor(s):
025:         *
026:         * The Original Software is NetBeans. The Initial Developer of the Original
027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028:         * Microsystems, Inc. All Rights Reserved.
029:         *
030:         * If you wish your version of this file to be governed by only the CDDL
031:         * or only the GPL Version 2, indicate your decision by adding
032:         * "[Contributor] elects to include this software in this distribution
033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
034:         * single choice of license, a recipient has the option to distribute
035:         * your version of this file under either the CDDL, the GPL Version 2 or
036:         * to extend the choice of license to its licensees as provided above.
037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
038:         * Version 2 license, then the option applies only if the new code is
039:         * made subject to such option by the copyright holder.
040:         */
041:
042:        package org.netbeans.modules.subversion;
043:
044:        import javax.swing.SwingUtilities;
045:        import org.netbeans.modules.subversion.util.FileUtils;
046:        import org.netbeans.modules.subversion.util.SvnUtils;
047:        import org.netbeans.modules.subversion.client.SvnClient;
048:        import java.io.File;
049:        import java.io.IOException;
050:        import java.util.*;
051:        import java.util.logging.Level;
052:        import org.netbeans.modules.subversion.client.SvnClientExceptionHandler;
053:        import org.netbeans.modules.versioning.spi.VCSInterceptor;
054:        import org.netbeans.modules.versioning.util.Utils;
055:        import org.tigris.subversion.svnclientadapter.*;
056:
057:        /**
058:         * Handles events fired from the filesystem such as file/folder create/delete/move.
059:         * 
060:         * @author Maros Sandor
061:         */
062:        class FilesystemHandler extends VCSInterceptor {
063:
064:            private final Subversion svn;
065:            private final FileStatusCache cache;
066:
067:            /**
068:             * Stores .svn folders that should be deleted ASAP.
069:             */
070:            private final Set<File> invalidMetadata = new HashSet<File>(5);
071:
072:            public FilesystemHandler(Subversion svn) {
073:                this .svn = svn;
074:                cache = svn.getStatusCache();
075:            }
076:
077:            public boolean beforeDelete(File file) {
078:                Subversion.LOG.fine("beforeDelete " + file);
079:                if (SvnUtils.isPartOfSubversionMetadata(file))
080:                    return true;
081:                // calling cache results in SOE, we must check manually
082:                return !file.isFile() && hasMetadata(file);
083:            }
084:
085:            /**
086:             * This interceptor ensures that subversion metadata is NOT deleted. 
087:             * 
088:             * @param file file to delete
089:             */
090:            public void doDelete(File file) throws IOException {
091:                Subversion.LOG.fine("doDelete " + file);
092:                boolean isMetadata = SvnUtils.isPartOfSubversionMetadata(file);
093:                if (!isMetadata) {
094:                    remove(file);
095:                }
096:            }
097:
098:            public void afterDelete(final File file) {
099:                Subversion.LOG.fine("afterDelete " + file);
100:                Utils.post(new Runnable() {
101:                    public void run() {
102:                        // If a regular file is deleted then update its Entries as if it has been removed.
103:                        if (file == null)
104:                            return;
105:                        int status = cache.getStatus(file).getStatus();
106:                        if (status != FileInformation.STATUS_NOTVERSIONED_EXCLUDED
107:                                && status != FileInformation.STATUS_NOTVERSIONED_NEWLOCALLY) {
108:                            try {
109:                                SvnClient client = Subversion.getInstance()
110:                                        .getClient(false);
111:                                client.remove(new File[] { file }, true);
112:
113:                            } catch (SVNClientException e) {
114:                                // ignore; we do not know what to do here; does no harm, the file was probably Locally New
115:                            }
116:                        }
117:                        // fire event explicitly because the file is already gone
118:                        // so svnClientAdapter does not fire ISVNNotifyListener event
119:                        cache.refresh(file,
120:                                FileStatusCache.REPOSITORY_STATUS_UNKNOWN);
121:                    }
122:                });
123:            }
124:
125:            public boolean beforeMove(File from, File to) {
126:                Subversion.LOG.fine("beforeMove " + from + " -> " + to);
127:                File destDir = to.getParentFile();
128:                if (from != null && destDir != null) {
129:                    // a direct cache call could, because of the synchrone beforeMove handling, 
130:                    // trigger an reentrant call on FS => we have to check manually            
131:                    if (isVersioned(from)) {
132:                        return Subversion.getInstance().isManaged(to);
133:                    }
134:                    // else XXX handle file with saved administative
135:                    // right now they have old status in cache but is it guaranteed?
136:                }
137:
138:                return false;
139:            }
140:
141:            public void doMove(final File from, final File to)
142:                    throws IOException {
143:                Subversion.LOG.fine("doMove " + from + " -> " + to);
144:                if (SwingUtilities.isEventDispatchThread()) {
145:
146:                    Subversion.LOG.log(Level.INFO,
147:                            "Warning: launching external process in AWT",
148:                            new Exception().fillInStackTrace());
149:                    final Throwable innerT[] = new Throwable[1];
150:                    Runnable outOfAwt = new Runnable() {
151:                        public void run() {
152:                            try {
153:                                svnMoveImplementation(from, to);
154:                            } catch (Throwable t) {
155:                                innerT[0] = t;
156:                            }
157:                        }
158:                    };
159:
160:                    Subversion.getInstance().getRequestProcessor().post(
161:                            outOfAwt).waitFinished();
162:                    if (innerT[0] != null) {
163:                        if (innerT[0] instanceof  IOException) {
164:                            throw (IOException) innerT[0];
165:                        } else if (innerT[0] instanceof  RuntimeException) {
166:                            throw (RuntimeException) innerT[0];
167:                        } else if (innerT[0] instanceof  Error) {
168:                            throw (Error) innerT[0];
169:                        } else {
170:                            throw new IllegalStateException(
171:                                    "Unexpected exception class: " + innerT[0]); // NOI18N
172:                        }
173:                    }
174:
175:                    // end of hack
176:
177:                } else {
178:                    svnMoveImplementation(from, to);
179:                }
180:            }
181:
182:            public void afterMove(final File from, final File to) {
183:                Subversion.LOG.fine("afterMove " + from + " -> " + to);
184:                Utils.post(new Runnable() {
185:                    public void run() {
186:                        // there might have been no notification 
187:                        // for the children files - refresh them all
188:                        SvnUtils.refreshRecursively(to);
189:                        cache.onNotify(to, null); // as if there were an event
190:                        File parent = to.getParentFile();
191:                        if (parent != null) {
192:                            if (from.equals(to)) {
193:                                Subversion.LOG
194:                                        .warning("Wrong (identity) rename event for "
195:                                                + from.getAbsolutePath());
196:                            }
197:                            cache.onNotify(from, null); // as if there were an event
198:                        }
199:                    }
200:                });
201:            }
202:
203:            public boolean beforeCreate(File file, boolean isDirectory) {
204:                Subversion.LOG.fine("beforeCreate " + file);
205:                if (SvnUtils.isPartOfSubversionMetadata(file)) {
206:                    synchronized (invalidMetadata) {
207:                        File p = file;
208:                        while (!p.getName().equals(".svn")
209:                                && !p.getName().equals("_svn")) {
210:                            p = p.getParentFile();
211:                            assert p != null : "file " + file
212:                                    + " doesn't have a .svn parent";
213:                        }
214:                        invalidMetadata.add(p);
215:                    }
216:                    return false;
217:                } else {
218:                    if (!file.exists()) {
219:                        try {
220:                            SvnClient client = Subversion.getInstance()
221:                                    .getClient(true);
222:                            // check if the file wasn't just deleted in this session
223:                            revertDeleted(client, file, true);
224:                        } catch (SVNClientException ex) {
225:                            SvnClientExceptionHandler.notifyException(ex,
226:                                    false, false);
227:                        }
228:                    }
229:                    return false;
230:                }
231:            }
232:
233:            /**
234:             * Returns all direct parent folders from the given file which are scheduled for deletion
235:             * 
236:             * @param file
237:             * @param client
238:             * @return a list of folders 
239:             * @throws org.tigris.subversion.svnclientadapter.SVNClientException
240:             */
241:            private static List<File> getDeletedParents(File file,
242:                    SvnClient client) throws SVNClientException {
243:                List<File> ret = new ArrayList<File>();
244:                for (File parent = file.getParentFile(); parent != null; parent = parent
245:                        .getParentFile()) {
246:                    ISVNStatus status = getStatus(client, parent);
247:                    if (status == null
248:                            || !status.getTextStatus().equals(
249:                                    SVNStatusKind.DELETED)) {
250:                        return ret;
251:                    }
252:                    ret.add(parent);
253:                }
254:                return ret;
255:            }
256:
257:            public void doCreate(File file, boolean isDirectory)
258:                    throws IOException {
259:                // do nothing
260:            }
261:
262:            public void afterCreate(final File file) {
263:                Subversion.LOG.fine("afterCreate " + file);
264:                Utils.post(new Runnable() {
265:                    public void run() {
266:                        if (file == null)
267:                            return;
268:                        int status = cache.refresh(file,
269:                                FileStatusCache.REPOSITORY_STATUS_UNKNOWN)
270:                                .getStatus();
271:                        if ((status & FileInformation.STATUS_MANAGED) == 0) {
272:                            return;
273:                        }
274:                        if (file.isDirectory())
275:                            cache.directoryContentChanged(file);
276:                    }
277:                });
278:            }
279:
280:            public void afterChange(final File file) {
281:                Subversion.LOG.fine("afterChange " + file);
282:                Utils.post(new Runnable() {
283:                    public void run() {
284:                        if ((cache.getStatus(file).getStatus() & FileInformation.STATUS_MANAGED) != 0) {
285:                            cache.refreshCached(file,
286:                                    FileStatusCache.REPOSITORY_STATUS_UNKNOWN);
287:                        }
288:                    }
289:                });
290:            }
291:
292:            /**
293:             * Removes invalid metadata from all known folders.
294:             */
295:            void removeInvalidMetadata() {
296:                synchronized (invalidMetadata) {
297:                    for (File file : invalidMetadata) {
298:                        Utils.deleteRecursively(file);
299:                    }
300:                    invalidMetadata.clear();
301:                }
302:            }
303:
304:            // private methods ---------------------------
305:
306:            private boolean hasMetadata(File file) {
307:                return new File(file, ".svn/entries").canRead()
308:                        || new File(file, "_svn/entries").canRead();
309:            }
310:
311:            private boolean isVersioned(File file) {
312:                if (SvnUtils.isPartOfSubversionMetadata(file))
313:                    return false;
314:                return (!file.isFile() && hasMetadata(file))
315:                        || (file.isFile() && hasMetadata(file.getParentFile()));
316:            }
317:
318:            private boolean remove(File file) {
319:                try {
320:                    SvnClient client = Subversion.getInstance()
321:                            .getClient(false);
322:                    // funny thing is, the command will delete all files recursively
323:                    client.remove(new File[] { file }, true);
324:                    return true;
325:                } catch (SVNClientException e) {
326:                    return false;
327:                }
328:            }
329:
330:            private void revertDeleted(SvnClient client, final File file,
331:                    boolean checkParents) {
332:
333:                try {
334:                    ISVNStatus status = getStatus(client, file);
335:                    if (status != null
336:                            && status.getTextStatus().equals(
337:                                    SVNStatusKind.DELETED)) {
338:                        if (checkParents) {
339:                            // we have a file scheduled for deletion but it's giong to created again,
340:                            // so it's parent folder can't stay deleted either
341:                            List<File> deletedParents = getDeletedParents(file,
342:                                    client);
343:                            client.revert(deletedParents
344:                                    .toArray(new File[deletedParents.size()]),
345:                                    false);
346:                        }
347:
348:                        // reverting the file will set the metadata uptodate
349:                        client.revert(file, false);
350:                        // our goal was ony to fix the metadata ->
351:                        //  -> get rid of the reverted file
352:                        file.delete();
353:                    }
354:                } catch (SVNClientException ex) {
355:                    SvnClientExceptionHandler.notifyException(ex, false, false);
356:                }
357:            }
358:
359:            private void svnMoveImplementation(final File srcFile,
360:                    final File dstFile) throws IOException {
361:                try {
362:                    boolean force = true; // file with local changes must be forced
363:                    SvnClient client = Subversion.getInstance()
364:                            .getClient(false);
365:
366:                    File tmpMetadata = null;
367:                    try {
368:                        // prepare destination, it must be under Subversion control
369:                        removeInvalidMetadata();
370:
371:                        File parent;
372:                        if (dstFile.isDirectory()) {
373:                            parent = dstFile;
374:                        } else {
375:                            parent = dstFile.getParentFile();
376:                        }
377:
378:                        if (parent != null) {
379:                            assert Subversion.getInstance().isManaged(parent); // see implsMove above                                        
380:                            // a direct cache call could, because of the synchrone svnMoveImplementation handling, 
381:                            // trigger an reentrant call on FS => we have to check manually            
382:                            if (!hasMetadata(parent)) {
383:                                addDirectories(parent);
384:                            }
385:                        }
386:
387:                        // perform
388:                        int retryCounter = 6;
389:                        while (true) {
390:                            try {
391:                                // check if the file wasn't just deleted in this session
392:                                revertDeleted(client, dstFile, false);
393:
394:                                // check the status - if the file isn't in the repository yet ( ADDED | UNVERSIONED )
395:                                // then it also can't be moved via the svn client
396:                                ISVNStatus status = getStatus(client, srcFile);
397:                                if (status != null
398:                                        && status.getTextStatus().equals(
399:                                                SVNStatusKind.ADDED)) {
400:                                    client.revert(srcFile, true);
401:                                    renameFile(srcFile, dstFile);
402:                                } else if (status != null
403:                                        && status.getTextStatus().equals(
404:                                                SVNStatusKind.UNVERSIONED)) {
405:                                    renameFile(srcFile, dstFile);
406:                                } else {
407:                                    List<File> srcChildren = listAllChildren(srcFile);
408:                                    client.move(srcFile, dstFile, force);
409:
410:                                    // fire events explicitly for all children which are already gone
411:                                    for (File f : srcChildren) {
412:                                        cache.onNotify(f, null);
413:                                    }
414:                                }
415:
416:                                break;
417:                            } catch (SVNClientException e) {
418:                                // svn: Working copy '/tmp/co/svn-prename-19/AnagramGame-pack-rename/src/com/toy/anagrams/ui2' locked
419:                                if (e.getMessage().endsWith("' locked")
420:                                        && retryCounter > 0) { // NOI18N
421:                                    // XXX HACK AWT- or FS Monitor Thread performs
422:                                    // concurrent operation
423:                                    try {
424:                                        Thread.sleep(107);
425:                                    } catch (InterruptedException ex) {
426:                                        // ignore
427:                                    }
428:                                    retryCounter--;
429:                                    continue;
430:                                }
431:
432:                                IOException ex = new IOException(
433:                                        "Subversion failed to rename "
434:                                                + srcFile.getAbsolutePath()
435:                                                + " to: "
436:                                                + dstFile.getAbsolutePath()); // NOI18N
437:                                ex.initCause(e);
438:                                throw ex;
439:
440:                            }
441:                        }
442:                    } finally {
443:                        if (tmpMetadata != null) {
444:                            FileUtils.deleteRecursively(tmpMetadata);
445:                        }
446:                    }
447:                } catch (SVNClientException e) {
448:                    IOException ex = new IOException(
449:                            "Subversion failed to rename "
450:                                    + srcFile.getAbsolutePath() + " to: "
451:                                    + dstFile.getAbsolutePath()); // NOI18N
452:                    ex.initCause(e);
453:                    throw ex;
454:                }
455:            }
456:
457:            private void renameFile(File srcFile, File dstFile) {
458:                List<File> srcChildren = listAllChildren(srcFile);
459:                srcFile.renameTo(dstFile);
460:
461:                // notify the cache
462:                cache.onNotify(srcFile, null);
463:                for (File f : srcChildren) {
464:                    // fire events explicitly for 
465:                    // all children which are already gone
466:                    cache.onNotify(f, null);
467:                }
468:                cache.onNotify(dstFile, null);
469:            }
470:
471:            private List<File> listAllChildren(File file) {
472:                if (file.isFile())
473:                    return new ArrayList<File>(0);
474:                List<File> ret = new ArrayList<File>();
475:                File[] files = file.listFiles();
476:                if (files != null) {
477:                    for (File f : files) {
478:                        ret.add(f);
479:                        ret.addAll(listAllChildren(f));
480:                    }
481:                }
482:                return ret;
483:            }
484:
485:            /**
486:             * Seeks versioned root and then adds all folders
487:             * under Subversion (so it contains metadata),
488:             */
489:            private void addDirectories(final File dir)
490:                    throws SVNClientException {
491:                File parent = dir.getParentFile();
492:                if (parent != null) {
493:                    if (Subversion.getInstance().isManaged(parent)
494:                            && !hasMetadata(parent)) {
495:                        addDirectories(parent); // RECURSION
496:                    }
497:                    SvnClient client = Subversion.getInstance()
498:                            .getClient(false);
499:                    client.addDirectory(dir, false);
500:                    Utils.post(new Runnable() {
501:                        public void run() {
502:                            cache.refresh(dir,
503:                                    FileStatusCache.REPOSITORY_STATUS_UNKNOWN);
504:                        }
505:                    });
506:                } else {
507:                    throw new SVNClientException(
508:                            "Reached FS root, but it's still not Subversion versioned!"); // NOI18N
509:                }
510:            }
511:
512:            private static ISVNStatus getStatus(SvnClient client, File file)
513:                    throws SVNClientException {
514:                // a direct cache call could, because of the synchrone beforeCreate handling, 
515:                // trigger an reentrant call on FS => we have to check manually 
516:                return client.getSingleStatus(file);
517:            }
518:
519:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.