This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 196886
Collapse All | Expand All

(-)a/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fs/RemoteDirectory.java (+226 lines)
Lines 79-84 Link Here
79
import org.openide.filesystems.FileEvent;
79
import org.openide.filesystems.FileEvent;
80
import org.openide.filesystems.FileLock;
80
import org.openide.filesystems.FileLock;
81
import org.openide.filesystems.FileObject;
81
import org.openide.filesystems.FileObject;
82
import org.openide.filesystems.FileRenameEvent;
82
import org.openide.util.Exceptions;
83
import org.openide.util.Exceptions;
83
84
84
/**
85
/**
Lines 533-538 Link Here
533
        return true;
534
        return true;
534
    }
535
    }
535
    
536
    
537
    @Override
538
    protected final void renameChild(FileLock lock, RemoteFileObjectBase directChild2Rename, String newNameExt) throws 
539
            ConnectException, IOException, InterruptedException, CancellationException, ExecutionException {
540
        String nameExt2Rename = directChild2Rename.getNameExt();
541
        String name2Rename = directChild2Rename.getName();
542
        String ext2Rename = directChild2Rename.getExt();
543
        String path2Rename = directChild2Rename.getPath();
544
        File storageFile = new File(getCache(), RemoteFileSystem.CACHE_FILE_NAME);
545
546
        checkConnection(this, true);
547
548
        Lock writeLock = RemoteFileSystem.getLock(getCache()).writeLock();
549
        if (trace) {trace("waiting for lock");} // NOI18N
550
        writeLock.lock();
551
        try {
552
            DirectoryStorage storage = getExistingDirectoryStorage();
553
            boolean fromMemOrDiskCache = (storage != DirectoryStorage.EMPTY);
554
            if (!getCache().exists()) {
555
                getCache().mkdirs();
556
                if (!getCache().exists()) {
557
                    throw new IOException("Can not create cache directory " + getCache()); // NOI18N
558
                }
559
            }
560
            if (trace) {trace("renaming");} // NOI18N
561
            ProcessUtils.ExitStatus ret = ProcessUtils.executeInDir(getPath(), getExecutionEnvironment(), "mv", nameExt2Rename, newNameExt);// NOI18N
562
            if (!ret.isOK()) {
563
                throw new IOException(ret.error);
564
            }
565
            
566
            if (trace) {trace("synchronizing");} // NOI18N
567
            Exception problem = null;
568
            Map<String, DirEntry> newEntries = Collections.emptyMap();
569
            try {
570
                newEntries = readEntries(storage, true, newNameExt);
571
            } catch (FileNotFoundException ex) {
572
                throw ex;
573
            } catch (IOException ex) {
574
                problem = ex;
575
            } catch (ExecutionException ex) {
576
                problem = ex;
577
            }
578
            if (problem != null) {
579
                if (!ConnectionManager.getInstance().isConnectedTo(getExecutionEnvironment())) {
580
                    // connection was broken while we read directory content - add notification
581
                    getFileSystem().getRemoteFileSupport().addPendingFile(this);
582
                    throw new ConnectException(problem.getMessage());
583
                } else {
584
                    boolean fileNotFoundException = isFileNotFoundException(problem);
585
                    if (fileNotFoundException) {
586
                        synchronized (refLock) {
587
                            storageRef = new SoftReference<DirectoryStorage>(DirectoryStorage.EMPTY);
588
                        }
589
                    }
590
                    if (!fileNotFoundException) {
591
                        if (problem instanceof IOException) {
592
                            throw (IOException) problem;
593
                        } else if (problem instanceof ExecutionException) {
594
                            throw (ExecutionException) problem;
595
                        } else {
596
                            throw new IllegalStateException("Unexpected exception class: " + problem.getClass().getName(), problem); //NOI18N
597
                        }
598
                    }
599
                }
600
            }
601
            getFileSystem().incrementDirSyncCount();
602
            Map<String, List<DirEntry>> dupLowerNames = new HashMap<String, List<DirEntry>>();
603
            boolean hasDups = false;
604
            boolean changed = true;
605
            Set<DirEntry> keepCacheNames = new HashSet<DirEntry>();
606
            List<DirEntry> entriesToFireChanged = new ArrayList<DirEntry>();
607
            List<DirEntry> entriesToFireCreated = new ArrayList<DirEntry>();
608
            List<FileObject> filesToFireDeleted = new ArrayList<FileObject>();
609
            for (DirEntry newEntry : newEntries.values()) {
610
                if (newEntry.isValid()) {
611
                    String cacheName;
612
                    DirEntry oldEntry = storage.getValidEntry(newEntry.getName());
613
                    if (oldEntry == null || !oldEntry.isValid()) {
614
                        changed = true;
615
                        cacheName = RemoteFileSystemUtils.escapeFileName(newEntry.getName());
616
                        if (newEntry.getName().equals(newNameExt)) {
617
                            DirEntry renamedEntry = storage.getValidEntry(nameExt2Rename);
618
                            // NPE check?
619
                            cacheName = renamedEntry.getCache();
620
                        } else if (fromMemOrDiskCache) {
621
                            entriesToFireCreated.add(newEntry);
622
                        }
623
                    } else {
624
                        if (oldEntry.isSameType(newEntry)) {
625
                            cacheName = oldEntry.getCache();
626
                            keepCacheNames.add(newEntry);
627
                            boolean fire = false;
628
                            if (!newEntry.isSameLastModified(oldEntry)) {
629
                                if (newEntry.isPlainFile()) {
630
                                    changed = fire = true;
631
                                    File entryCache = new File(getCache(), oldEntry.getCache());
632
                                    if (entryCache.exists()) {
633
                                        if (trace) {
634
                                            trace("removing cache for updated file {0}", entryCache.getAbsolutePath());
635
                                        } // NOI18N
636
                                        entryCache.delete(); // TODO: We must just mark it as invalid instead of physically deleting cache file...
637
                                    }
638
                                }
639
                            } else if (!equals(newEntry.getLinkTarget(), oldEntry.getLinkTarget())) {
640
                                changed = fire = true; // TODO: we forgot old link path, probably should be passed to change event 
641
                                getFileSystem().getFactory().setLink(this, getPath() + '/' + newEntry.getName(), newEntry.getLinkTarget());
642
                            } else if (!newEntry.getAccessAsString().equals(oldEntry.getAccessAsString())) {
643
                                changed = fire = true;
644
                            } else if (!newEntry.isSameUser(oldEntry)) {
645
                                changed = fire = true;
646
                            } else if (!newEntry.isSameGroup(oldEntry)) {
647
                                changed = fire = true;
648
                            } else if (newEntry.getSize() != oldEntry.getSize()) {
649
                                changed = fire = true;// TODO: shouldn't it be the same as time stamp change?
650
                            }
651
                            if (fire) {
652
                                entriesToFireChanged.add(newEntry);
653
                            }
654
                        } else {
655
                            changed = true;
656
                            FileObject removedFO = invalidate(oldEntry);
657
                            // remove old
658
                            if (removedFO != null) {
659
                                filesToFireDeleted.add(removedFO);
660
                            }
661
                            // add new 
662
                            entriesToFireCreated.add(newEntry);
663
                            cacheName = RemoteFileSystemUtils.escapeFileName(newEntry.getName());
664
                        }
665
                    }
666
                    newEntry.setCache(cacheName);
667
                    if (!RemoteFileSystemUtils.isSystemCaseSensitive()) {
668
                        String lowerCacheName = newEntry.getCache().toLowerCase();
669
                        List<DirEntry> dupEntries = dupLowerNames.get(lowerCacheName);
670
                        if (dupEntries == null) {
671
                            dupEntries = new ArrayList<DirEntry>();
672
                            dupLowerNames.put(lowerCacheName, dupEntries);
673
                        } else {
674
                            hasDups = true;
675
                        }
676
                        dupEntries.add(newEntry);
677
                    }
678
                } else {
679
                    changed = true;
680
                }
681
            }
682
            if (changed) {
683
                // Check for removal
684
                for (DirEntry oldEntry : storage.listValid()) {
685
                    if (!oldEntry.getName().equals(nameExt2Rename)) {
686
                        DirEntry newEntry = newEntries.get(oldEntry.getName());
687
                        if (newEntry == null || !newEntry.isValid()) {
688
                            FileObject removedFO = invalidate(oldEntry);
689
                            if (removedFO != null) {
690
                                filesToFireDeleted.add(removedFO);
691
                            }
692
                        }
693
                    }
694
                }
695
                if (hasDups) {
696
                    for (Map.Entry<String, List<DirEntry>> mapEntry :
697
                            new ArrayList<Map.Entry<String, List<DirEntry>>>(dupLowerNames.entrySet())) {
698
699
                        List<DirEntry> dupEntries = mapEntry.getValue();
700
                        if (dupEntries.size() > 1) {
701
                            for (int i = 0; i < dupEntries.size(); i++) {
702
                                DirEntry entry = dupEntries.get(i);
703
                                if (keepCacheNames.contains(entry)) {
704
                                    continue; // keep the one that already exists
705
                                }
706
                                // all duplicates will have postfix
707
                                for (int j = 0; j < Integer.MAX_VALUE; j++) {
708
                                    String cacheName = mapEntry.getKey() + '_' + j;
709
                                    String lowerCacheName = cacheName.toLowerCase();
710
                                    if (!dupLowerNames.containsKey(lowerCacheName)) {
711
                                        if (trace) {
712
                                            trace("resolving cache names conflict in {0}: {1} -> {2}", // NOI18N
713
                                                    getCache().getAbsolutePath(), entry.getCache(), cacheName);
714
                                        }
715
                                        entry.setCache(cacheName);
716
                                        dupLowerNames.put(lowerCacheName, Collections.singletonList(entry));
717
                                        break;
718
                                    }
719
                                }
720
                            }
721
                        }
722
                    }
723
                }
724
                storage = new DirectoryStorage(storageFile, newEntries.values());
725
                storage.store();
726
            } else {
727
                storage.touch();
728
            }
729
            // always put new content in cache 
730
            // do it before firing events, to give liseners real content
731
            synchronized (refLock) {
732
                storageRef = new SoftReference<DirectoryStorage>(storage);
733
            }
734
            // fire all event under lock
735
            if (changed) {
736
                for (FileObject deleted : filesToFireDeleted) {
737
                    fireFileDeletedEvent(getListeners(), new FileEvent(this, deleted));
738
                }
739
                for (DirEntry entry : entriesToFireCreated) {
740
                    RemoteFileObjectBase fo = createFileObject(entry);
741
                    fireRemoteFileObjectCreated(fo);
742
                }
743
                for (DirEntry entry : entriesToFireChanged) {
744
                    RemoteFileObjectBase fo = getFileSystem().getFactory().getCachedFileObject(getPath() + '/' + entry.getName());
745
                    if (fo != null) {
746
                        fireFileChangedEvent(getListeners(), new FileEvent(fo));
747
                    }
748
                }
749
                // rename itself
750
                String newPath = getPath() + '/' + newNameExt;
751
                getFileSystem().getFactory().rename(path2Rename, newPath, directChild2Rename);
752
                // fire rename
753
                fireFileRenamedEvent(directChild2Rename.getListeners(), new FileRenameEvent(directChild2Rename, directChild2Rename, name2Rename, ext2Rename));
754
                fireFileRenamedEvent(this.getListeners(), new FileRenameEvent(this, directChild2Rename, name2Rename, ext2Rename));
755
                //fireFileChangedEvent(getListeners(), new FileEvent(this));
756
            }
757
        } finally {
758
            writeLock.unlock();
759
        }        
760
    }
761
536
    private DirectoryStorage getDirectoryStorageImpl(boolean forceRefresh, String expectedName, String childName) throws
762
    private DirectoryStorage getDirectoryStorageImpl(boolean forceRefresh, String expectedName, String childName) throws
537
            ConnectException, IOException, InterruptedException, CancellationException, ExecutionException {
763
            ConnectException, IOException, InterruptedException, CancellationException, ExecutionException {
538
764
(-)a/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fs/RemoteFileObjectBase.java (-2 / +41 lines)
Lines 72-78 Link Here
72
72
73
    private final RemoteFileSystem fileSystem;
73
    private final RemoteFileSystem fileSystem;
74
    private final RemoteFileObjectBase parent;
74
    private final RemoteFileObjectBase parent;
75
    private final String remotePath;
75
    private volatile String remotePath;
76
    private final File cache;
76
    private final File cache;
77
    private CopyOnWriteArrayList<FileChangeListener> listeners = new CopyOnWriteArrayList<FileChangeListener>();
77
    private CopyOnWriteArrayList<FileChangeListener> listeners = new CopyOnWriteArrayList<FileChangeListener>();
78
    private final FileLock lock = new FileLock();
78
    private final FileLock lock = new FileLock();
Lines 340-346 Link Here
340
340
341
    @Override
341
    @Override
342
    public void rename(FileLock lock, String name, String ext) throws IOException {
342
    public void rename(FileLock lock, String name, String ext) throws IOException {
343
        throw new ReadOnlyException();
343
        RemoteFileObjectBase p = getParent();
344
        if (p != null) {
345
            String newNameExt = composeName(name, ext);
346
            if (newNameExt.equals(getNameExt())) {
347
                // nothing to rename
348
                return;
349
            }
350
            if (!p.isValid()) {
351
                throw new IOException("Can not rename in " + p.getPath());//NOI18N
352
            }
353
            // Can not rename in read only folder
354
            if (!p.canWrite()) {
355
                throw new IOException("Can not rename in read only " + p.getPath());//NOI18N
356
            }
357
            // check there are no other child with such name
358
            if (p.getFileObject(newNameExt) != null) {
359
                throw new IOException("Can not rename to " + newNameExt);//NOI18N
360
            }
361
            
362
            if (!ConnectionManager.getInstance().isConnectedTo(getExecutionEnvironment())) {
363
                throw new IOException("No connection: Can not rename in " + p.getPath()); //NOI18N
364
            }
365
            try {
366
                p.renameChild(lock, this, newNameExt);
367
            } catch (ConnectException ex) {
368
                throw new IOException("No connection: Can not rename in " + p.getPath(), ex); //NOI18N
369
            } catch (InterruptedException ex) {
370
                throw new IOException("interrupted: Can not rename in " + p.getPath(), ex); //NOI18N
371
            } catch (CancellationException ex) {
372
                throw new IOException("cancelled: Can not rename in " + p.getPath(), ex); //NOI18N
373
            } catch (ExecutionException ex) {
374
                throw new IOException("Can not rename to " + newNameExt + ": exception occurred", ex); // NOI18N
375
            }
376
        }
344
    }
377
    }
345
378
346
    @Override
379
    @Override
Lines 365-370 Link Here
365
    }
398
    }
366
399
367
    public abstract FileType getType();
400
    public abstract FileType getType();
401
    protected abstract void renameChild(FileLock lock, RemoteFileObjectBase toRename, String newNameExt) 
402
            throws ConnectException, IOException, InterruptedException, CancellationException, ExecutionException;
403
404
    final void renamePath(String newPath) {
405
        this.remotePath = newPath;
406
    }
368
407
369
    private static class ReadOnlyException extends IOException {
408
    private static class ReadOnlyException extends IOException {
370
        public ReadOnlyException() {
409
        public ReadOnlyException() {
(-)a/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fs/RemoteFileObjectFactory.java (-2 / +8 lines)
Lines 84-90 Link Here
84
    public RemoteFileObjectBase getCachedFileObject(String path) {
84
    public RemoteFileObjectBase getCachedFileObject(String path) {
85
        return fileObjectsCache.get(path);
85
        return fileObjectsCache.get(path);
86
    }
86
    }
87
    
87
88
    private void scheduleCleanDeadEntries() {
88
    private void scheduleCleanDeadEntries() {
89
        cleaningTask.schedule(CLEAN_INTERVAL);
89
        cleaningTask.schedule(CLEAN_INTERVAL);
90
    }
90
    }
Lines 195-201 Link Here
195
        }
195
        }
196
        return fo;
196
        return fo;
197
    }
197
    }
198
198
    
199
    public void rename(String path2Rename, String newPath, RemoteFileObjectBase directChild2Rename) {
200
        fileObjectsCache.remove(path2Rename, directChild2Rename);
201
        directChild2Rename.renamePath(newPath);
202
        fileObjectsCache.putIfAbsent(newPath, directChild2Rename);
203
    }
204
        
199
    public void setLink(RemoteDirectory parent, String linkRemotePath, String linkTarget) {
205
    public void setLink(RemoteDirectory parent, String linkRemotePath, String linkTarget) {
200
        RemoteFileObjectBase fo = fileObjectsCache.get(linkRemotePath);
206
        RemoteFileObjectBase fo = fileObjectsCache.get(linkRemotePath);
201
        if (fo != null) {
207
        if (fo != null) {
(-)a/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fs/RemoteLinkBase.java (+16 lines)
Lines 215-220 Link Here
215
    }
215
    }
216
216
217
    @Override
217
    @Override
218
    public void rename(FileLock lock, String name, String ext) throws IOException {
219
        RemoteFileObjectBase delegate = getDelegate();
220
        if (delegate != null) {
221
            delegate.rename(lock, name, ext);
222
        } else {
223
            throw new IOException("can not rename " + getPath()); //NOI18N
224
        }
225
    }
226
227
    @Override
228
    protected void renameChild(FileLock lock, RemoteFileObjectBase toRename, String newNameExt) 
229
            throws ConnectException, IOException, InterruptedException, CancellationException, ExecutionException{
230
        throw new UnsupportedOperationException();
231
    }
232
    
233
    @Override
218
    public FileObject createFolder(String name) throws IOException {
234
    public FileObject createFolder(String name) throws IOException {
219
        RemoteFileObjectBase delegate = getDelegate();
235
        RemoteFileObjectBase delegate = getDelegate();
220
        if (delegate != null) {
236
        if (delegate != null) {
(-)a/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fs/RemotePlainFile.java (+6 lines)
Lines 167-172 Link Here
167
    }
167
    }
168
168
169
    @Override
169
    @Override
170
    protected void renameChild(FileLock lock, RemoteFileObjectBase toRename, String newNameExt) 
171
            throws ConnectException, IOException, InterruptedException, CancellationException, ExecutionException {
172
        throw new UnsupportedOperationException();
173
    }
174
175
    @Override
170
    public OutputStream getOutputStream(FileLock lock) throws IOException {
176
    public OutputStream getOutputStream(FileLock lock) throws IOException {
171
        if (!isValid()) {
177
        if (!isValid()) {
172
            throw new FileNotFoundException("FileObject " + this + " is not valid."); //NOI18N
178
            throw new FileNotFoundException("FileObject " + this + " is not valid."); //NOI18N

Return to bug 196886