1 19 20 package org.openide.filesystems; 21 22 import java.io.Externalizable ; 23 import java.io.IOException ; 24 import java.io.InputStream ; 25 import java.io.ObjectInput ; 26 import java.io.ObjectOutput ; 27 import java.io.OutputStream ; 28 import java.lang.ref.Reference ; 29 import java.lang.ref.WeakReference ; 30 import java.util.Collections ; 31 import java.util.Enumeration ; 32 import java.util.HashMap ; 33 import java.util.HashSet ; 34 import java.util.Iterator ; 35 import java.util.LinkedList ; 36 import java.util.List ; 37 import java.util.Map ; 38 import java.util.Properties ; 39 import java.util.Set ; 40 41 45 final class MultiFileObject extends AbstractFolder implements FileObject.PriorityFileChangeListener { 46 47 static final long serialVersionUID = -2343651324897646809L; 48 49 50 private static final char EXT_SEP = '.'; 51 52 53 private static final char PATH_SEP = '/'; 54 private static final FileSystem.AtomicAction markAtomicAction = new FileSystem.AtomicAction() { 55 public void run() { 56 } 57 }; 58 59 static final ThreadLocal <FileObject> attrAskedFileObject = new ThreadLocal <FileObject>(); 60 61 64 private Set delegates; 65 66 67 private FileObject leader; 68 69 70 private Reference <MfLock> lock; 71 72 73 private FileChangeListener weakL; 74 75 78 private FileObject lastAttrCacheFile; 79 private String lastAttrCacheName = ""; 81 87 public MultiFileObject(MultiFileSystem fs, MultiFileObject parent, String name) { 88 super(fs, parent, name); 89 90 weakL = org.openide.util.WeakListeners.create( 91 FileObject.PriorityFileChangeListener.class, FileChangeListener.class, this, null 92 ); 93 94 update(); 95 96 if (leader == null) { 97 leader = new AbstractFileObject.Invalid(name); 98 validFlag = false; 99 } 100 } 101 102 106 public MultiFileObject(MultiFileSystem fs) { 107 this(fs, null, ""); } 109 110 112 public FileSystem getLeaderFileSystem() throws FileStateInvalidException { 113 return leader.getFileSystem(); 114 } 115 116 117 private void freeLastAttrCache() { 118 lastAttrCacheFile = null; 119 lastAttrCacheName = ""; } 121 122 124 private void update() { 125 MultiFileSystem mfs = getMultiFileSystem(); 126 FileSystem[] arr = mfs.getDelegates(); 127 128 Set now = (delegates == null) ? Collections.EMPTY_SET : delegates; 129 Set <FileObject> del = new HashSet <FileObject>(arr.length * 2); 130 FileObject led = null; 131 132 String name = getPath(); 133 134 for (int i = 0; i < arr.length; i++) { 135 if (arr[i] != null) { 136 FileObject fo = mfs.findResourceOn(arr[i], name); 137 138 if (fo != null) { 139 del.add(fo); 140 141 if (!now.remove(fo)) { 142 fo.addFileChangeListener(weakL); 144 } 145 146 if ((led == null) && fo.isValid()) { 147 led = fo; 148 } 149 } 150 } 151 } 152 153 Iterator it = now.iterator(); 154 155 while (it.hasNext()) { 156 FileObject fo = (FileObject) it.next(); 157 fo.removeFileChangeListener(weakL); 158 } 159 160 if (led != null) { 161 if (!led.equals(this.leader) && (this.leader != null)) { 164 if (isData() && isValid()) { 166 fileChanged0(new FileEvent(this)); 167 } 168 169 getMultiFileSystem().notifyMigration(this); 170 } 171 172 this.leader = led; 173 } 174 175 this.delegates = del; 176 } 177 178 180 void updateAll() { 181 FileSystem mfs = getMultiFileSystem(); 182 183 try { 184 mfs.beginAtomicAction(); 185 186 Enumeration <AbstractFolder> en = existingSubFiles(true); 188 189 while (en.hasMoreElements()) { 190 MultiFileObject mfo = (MultiFileObject) en.nextElement(); 191 192 if (mfo.isFolder() && !mfo.isInitialized()) { 193 continue; 194 } 195 196 mfo.freeLastAttrCache(); 197 mfo.superRefresh(true); 198 } 199 } finally { 200 mfs.finishAtomicAction(); 201 } 202 } 203 204 209 void updateAllAfterSetDelegates(FileSystem[] oldFileSystems) { 210 try { 211 getMultiFileSystem().beginAtomicAction(); 212 213 FileSystem[] fileSystems = getMultiFileSystem().getDelegates(); 214 Enumeration <AbstractFolder> en = existingSubFiles(true); 215 216 while (en.hasMoreElements()) { 217 MultiFileObject mfo = (MultiFileObject) en.nextElement(); 218 219 if (mfo.isFolder() && !mfo.isInitialized()) { 220 continue; 221 } 222 223 if (mfo.hasListeners()) { 224 String path = mfo.getPath(); 225 FileObject oldLeader = findLeader(oldFileSystems, path); 226 FileObject newLeader = findLeader(fileSystems, path); 227 228 if ((oldLeader != null) && (newLeader != null) && !oldLeader.equals(newLeader)) { 229 mfo.fileAttributeChanged0(new FileAttributeEvent(mfo, null, null, null)); 230 } 231 } 232 233 mfo.freeLastAttrCache(); 234 mfo.refresh(true); 235 } 236 } finally { 237 getMultiFileSystem().finishAtomicAction(); 238 } 239 } 240 241 private void refreshAfterEvent(FileEvent fe) { 242 FileObject fFile = fe.getFile(); 243 superRefresh(false); 244 245 MultiFileObject mFile = (MultiFileObject) getFileObject(fFile.getName(), fFile.getExt()); 246 247 if (mFile != null) { 248 mFile.superRefresh(false); 249 } 250 } 251 252 private void superRefresh(boolean expected) { 253 super.refresh(expected); 254 } 255 256 private FileObject findLeader(FileSystem[] fs, String path) { 257 MultiFileSystem mfs = getMultiFileSystem(); 258 259 for (int i = 0; i < fs.length; i++) { 260 FileObject fo = mfs.findResourceOn(fs[i], path); 261 262 if (fo != null) { 263 return fo; 264 } 265 } 266 267 return null; 268 } 269 270 271 private MultiFileSystem getMultiFileSystem() { 272 return (MultiFileSystem) getFileSystem(); 273 } 274 275 277 private MultiFileObject getMultiChild(String name) { 278 return (MultiFileObject) getChild(name); 279 } 280 281 287 private FileObject writable() throws IOException { 288 MultiFileSystem fs = getMultiFileSystem(); 289 FileSystem single = fs.createWritableOn(getPath()); 290 291 if (single != leader.getFileSystem()) { 292 if (leader.isFolder()) { 295 leader = FileUtil.createFolder(root(single), getPath()); 296 } else { 297 FileObject folder = FileUtil.createFolder(root(single), getParent().getPath()); 298 leader = leader.copy(folder, leader.getName(), leader.getExt()); 299 } 300 301 MfLock l = ((lock == null) ? null : lock.get()); 302 303 if (l != null) { 304 l.addLock(leader); 306 } 307 } 308 309 return leader; 310 } 311 312 315 private Enumeration <FileObject> delegates() { 316 return getMultiFileSystem().delegates(getPath()); 317 } 318 319 325 private static void updateFoldersLock(FileObject fo) 326 throws IOException { 327 while (fo != null) { 328 MultiFileObject mfo = (MultiFileObject) fo; 329 330 MfLock l = (mfo.lock == null) ? null : mfo.lock.get(); 331 332 if (l != null) { 333 mfo.writable(); 335 } 336 337 fo = fo.getParent(); 338 } 339 } 340 341 345 349 protected final String [] list() { 350 Properties exclude = new Properties (); 351 List <String > addList = new LinkedList <String >(); 352 Set <String > addSet = new HashSet <String >(101); 353 354 Enumeration <FileObject> it = delegates(); 355 356 while (it.hasMoreElements()) { 358 FileObject folder = it.nextElement(); 359 360 if ((folder == null) || !folder.isFolder()) { 361 continue; 362 } 363 364 FileObject[] arr = folder.getChildren(); 365 Properties local = null; 366 367 for (int i = 0; i < arr.length; i++) { 368 String name = arr[i].getNameExt(); 369 370 if (name.endsWith(MultiFileSystem.MASK)) { 371 String basename = name.substring(0, name.length() - MultiFileSystem.MASK.length()); 372 373 if (local == null) { 375 local = new Properties (exclude); 376 } 377 378 local.setProperty(basename, basename); 379 380 if (!getMultiFileSystem().getPropagateMasks()) { 381 continue; 385 } 386 } 387 388 if (!addSet.contains(name) && (exclude.getProperty(name) == null)) { 391 addSet.add(name); 392 addList.add(name); 393 } 394 } 395 396 if (local != null) { 398 exclude = local; 399 } 400 } 401 402 if (getMultiFileSystem().getPropagateMasks()) { 403 addList.removeAll(exclude.keySet()); 406 } 407 408 String [] res = addList.toArray(new String [addList.size()]); 409 410 return res; 411 } 412 413 415 416 417 420 protected void refresh(String add, String remove, boolean fire, boolean expected) { 421 try { 422 getFileSystem().beginAtomicAction(); 423 424 synchronized (this) { 425 update(); 426 427 428 429 super.refresh(add, remove, fire, expected); 431 } 432 433 validFlag &= leader.isValid(); 434 } finally { 435 getFileSystem().finishAtomicAction(); 436 } 437 } 438 439 443 protected final AbstractFolder createFile(String name) { 444 return new MultiFileObject(getMultiFileSystem(), this, name); 445 } 446 447 451 454 public boolean isFolder() { 455 return (parent == null) || leader.isFolder(); 456 } 457 458 462 public java.util.Date lastModified() { 463 return leader.lastModified(); 464 } 465 466 470 public boolean isData() { 471 return leader.isData(); 472 } 473 474 477 public boolean isVirtual() { 478 return leader.isVirtual(); 479 } 480 481 @Deprecated public boolean isReadOnly() { 483 MultiFileSystem fs = getMultiFileSystem(); 484 485 if (fs.isReadOnly()) { 486 return true; 487 } 488 489 if (leader.isReadOnly()) { 490 try { 492 FileSystem simple = fs.createWritableOn(getPath()); 493 494 return simple == leader.getFileSystem(); 495 } catch (IOException e) { 496 return true; 497 } 498 } 499 500 return false; 501 } 502 503 public boolean canWrite() { 504 MultiFileSystem fs = getMultiFileSystem(); 505 506 if (fs.isReadOnly()) { 507 return false; 508 } 509 510 if (!leader.canWrite()) { 511 try { 513 FileSystem simple = fs.createWritableOn(getPath()); 514 515 return simple != leader.getFileSystem(); 516 } catch (IOException e) { 517 return false; 518 } 519 } 520 521 return true; 522 } 523 524 532 public String getMIMEType() { 533 return leader.getMIMEType(); 534 } 535 536 540 public long getSize() { 541 return leader.getSize(); 542 } 543 544 549 public InputStream getInputStream() throws java.io.FileNotFoundException { 550 return leader.getInputStream(); 551 } 552 553 559 public OutputStream getOutputStream(FileLock lock) 560 throws java.io.IOException { 561 MfLock l; 562 FileLock lWritable; 563 FileObject fo; 564 565 try { 566 getFileSystem().beginAtomicAction(markAtomicAction); 567 568 synchronized (this) { 569 l = testLock(lock); 570 571 fo = writable(); 573 lWritable = l.findLock(fo); 574 } 575 576 return fo.getOutputStream(lWritable); 577 } finally { 578 getFileSystem().finishAtomicAction(); 579 } 580 } 581 582 586 public synchronized FileLock lock() throws IOException { 587 if (lock != null) { 588 FileLock f = (FileLock) lock.get(); 589 590 if (f != null) { 591 throw new FileAlreadyLockedException(getPath()); 593 } 594 } 595 596 java.util.Set set = getMultiFileSystem().createLocksOn(getPath()); 597 MfLock l = new MfLock(leader, delegates(), set); 598 599 lock = new WeakReference <MfLock>(l); 600 601 return l; 604 } 605 606 610 private MfLock testLock(FileLock l) throws java.io.IOException { 611 if (lock == null) { 612 FSException.io("EXC_InvalidLock", l, getPath(), getMultiFileSystem().getDisplayName(), lock); } 614 615 if (lock.get() != l) { 616 FSException.io("EXC_InvalidLock", l, getPath(), getMultiFileSystem().getDisplayName(), lock.get()); } 618 619 return (MfLock) l; 620 } 621 622 @Deprecated public void setImportant(boolean b) { 624 Enumeration <FileObject> en = delegates(); 625 626 while (en.hasMoreElements()) { 627 FileObject fo = en.nextElement(); 628 fo.setImportant(b); 629 } 630 631 if (!b) { 632 getMultiFileSystem().markUnimportant(this); 633 } 634 } 635 636 637 private static final Object voidify(Object o) { 638 if (o == null) { 639 return new VoidValue(0); 640 } else if (o instanceof VoidValue) { 641 VoidValue vv = (VoidValue) o; 642 643 return new VoidValue(vv.level + 1); 644 } else { 645 return o; 646 } 647 } 648 649 650 private static final Object devoidify(Object o) { 651 if (o instanceof VoidValue) { 652 VoidValue vv = (VoidValue) o; 653 654 if (vv.level == 0) { 655 return null; 656 } else { 657 return new VoidValue(vv.level - 1); 658 } 659 } else { 660 return o; 661 } 662 } 663 664 668 public Object getAttribute(String attrName) { 669 return getAttribute(attrName, getPath()); 671 } 672 673 private final Object getAttribute(String attrName, String path) { 674 String prefixattr = ((path.length() == 0) ? null : (path.replace('/', '\\') + '\\' + attrName)); 683 684 { 685 686 Object oPerf; 687 FileObject localFo = lastAttrCacheFile; 688 String cachedAttrName = lastAttrCacheName; 689 690 if ((localFo != null) && !localFo.equals(this) && cachedAttrName.equals(attrName)) { 691 if (localFo.isRoot() && (prefixattr != null)) { 692 try { 693 FileSystem foFs = localFo.getFileSystem(); 694 695 if (!(foFs instanceof XMLFileSystem)) { 696 localFo = foFs.getRoot(); 697 oPerf = getAttribute(localFo, prefixattr, ""); 699 if (oPerf != null) { 700 return devoidify(oPerf); 701 } 702 } 703 } catch (FileStateInvalidException fiex) { 704 } 706 } 707 708 711 oPerf = getAttribute(localFo, attrName, localFo.getPath()); 712 713 if (oPerf != null) { 714 return devoidify(oPerf); 715 } 716 } 717 } 718 719 FileSystem[] systems = getMultiFileSystem().getDelegates(); 720 FileSystem leaderfs; 721 722 try { 723 leaderfs = getLeaderFileSystem(); 724 } catch (FileStateInvalidException fsie) { 725 leaderfs = null; 727 } 728 729 for (int i = 0; i < systems.length; i++) { 731 if (systems[i] == null) { 732 continue; 733 } 734 735 FileObject fo = getMultiFileSystem().findResourceOn(systems[i], path); 743 744 if (fo != null) { 745 Object o = getAttribute(fo, attrName, fo.getPath()); 747 if (o != null) { 748 return devoidify(o); 749 } 750 } 751 752 if ((prefixattr != null) && !(systems[i] instanceof XMLFileSystem)) { 757 fo = systems[i].getRoot(); 758 759 Object o = getAttribute(fo, prefixattr, ""); 761 if (o != null) { 762 return devoidify(o); 763 } 764 } 765 } 766 767 return null; 768 } 769 770 private Object getAttribute(FileObject fo, String attrName, String path) { 771 Object o; 772 773 FileObject topFO = attrAskedFileObject.get(); 774 775 if (topFO == null) { 776 attrAskedFileObject.set(this); 777 } 778 779 try { 780 if (fo instanceof MultiFileObject) { 781 o = ((MultiFileObject) fo).getAttribute(attrName, path); 782 } else if (fo instanceof AbstractFileObject) { 783 o = ((AbstractFileObject) fo).getAttribute(attrName, path); 784 } else { 785 o = fo.getAttribute(attrName); 786 } 787 } finally { 788 if (topFO == null) { 789 attrAskedFileObject.set(null); 790 } 791 } 792 793 if (o != null) { 794 lastAttrCacheFile = fo; 795 lastAttrCacheName = attrName; 796 } 797 798 return o; 799 } 800 801 806 public void setAttribute(String attrName, Object value) 807 throws IOException { 808 setAttribute(attrName, value, true); } 810 811 814 void setAttribute(String attrName, Object value, boolean fire) 815 throws IOException { 816 String path = getPath(); 820 FileSystem fs = getMultiFileSystem().createWritableOn(path); 821 FileObject fo = getMultiFileSystem().findResourceOn(fs, path); 822 Object oldValue = null; 823 String attrToSet = attrName; 824 825 if (fire) { 826 oldValue = getAttribute(attrName); 827 } 828 829 if (fo == null) { 830 fo = fs.getRoot(); 831 attrToSet = path.replace('/', '\\') + '\\' + attrName; 832 } 833 834 lastAttrCacheFile = fo; 835 lastAttrCacheName = attrToSet; 836 837 if (fo instanceof AbstractFolder) { 838 ((AbstractFolder) fo).setAttribute(attrToSet, voidify(value), false); 839 } else { 840 844 fire = fire && fo.isRoot(); 845 fo.setAttribute(attrToSet, voidify(value)); 846 } 847 848 851 856 if (fire && (oldValue != value) && hasAtLeastOneListeners()) { 857 fileAttributeChanged0(new FileAttributeEvent(this, attrName, oldValue, value)); 858 } 859 } 860 861 864 public Enumeration <String > getAttributes() { 865 return getAttributes(getPath()); 866 } 867 868 private final Enumeration <String > getAttributes(String path) { 869 Set <String > s = new HashSet <String >(); 870 FileSystem[] systems = getMultiFileSystem().getDelegates(); 871 872 String prefix = (path.length() == 0) ? null : (path.replace('/', '\\') + '\\'); 875 876 for (int i = 0; i < systems.length; i++) { 877 if (systems[i] == null) { 878 continue; 879 } 880 881 FileObject fo = getMultiFileSystem().findResourceOn(systems[i], path); 882 883 if (fo != null) { 884 Enumeration <String > e = fo.getAttributes(); 885 886 while (e.hasMoreElements()) { 887 String attr = e.nextElement(); 888 s.add(attr); 889 } 890 } 891 892 if (prefix != null) { 893 fo = systems[i].getRoot(); 894 895 Enumeration <String > e; 896 897 if (fo instanceof MultiFileObject) { 898 e = ((MultiFileObject) fo).getAttributes(""); } else if (fo instanceof AbstractFileObject) { 900 e = ((AbstractFileObject) fo).getAttributes(""); } else { 902 e = fo.getAttributes(); 903 } 904 905 while (e.hasMoreElements()) { 906 String attr = e.nextElement(); 907 908 if (attr.startsWith(prefix) && (attr.substring(prefix.length()).indexOf('\\') == -1)) { 909 s.add(attr.substring(prefix.length())); 910 } 911 } 912 } 913 } 914 915 return Collections.enumeration(s); 916 } 917 918 925 public FileObject createFolder(String name) throws IOException { 926 MultiFileObject fo; 927 928 try { 929 getFileSystem().beginAtomicAction(); 930 931 synchronized (this) { 932 MultiFileSystem fs = getMultiFileSystem(); 933 934 if (fs.isReadOnly()) { 935 FSException.io("EXC_FSisRO", fs.getDisplayName()); } 937 938 if (isReadOnly()) { 939 FSException.io("EXC_FisRO", name, fs.getDisplayName()); } 941 942 String fullName = getPath() + PATH_SEP + name; 943 944 if (!isFolder()) { 945 FSException.io("EXC_FoNotFolder", name, getPath(), fs.getDisplayName()); } 947 948 if (this.getFileObject(name) != null) { 949 FSException.io("EXC_FolderAlreadyExist", name, fs.getDisplayName()); } 951 952 FileSystem simple = fs.createWritableOn(fullName); 953 954 FileUtil.createFolder(root(simple), fullName); 956 957 getMultiFileSystem().unmaskFileOnAll(simple, fullName); 959 960 961 refresh(name, null, true, false); 963 964 fo = getMultiChild(name); 965 966 if (fo == null) { 967 throw new FileStateInvalidException( 969 FileSystem.getString("EXC_ApplicationCreateError", getPath(), name) 970 ); 971 } 972 973 FileObject[] chlds = fo.getChildren(); 974 975 for (int i = 0; i < chlds.length; i++) { 976 getMultiFileSystem().maskFile(simple, chlds[i].getPath()); 977 } 978 979 if (hasListeners()) { 980 fileCreated0(new FileEvent(this, fo), false); 981 } 982 } 983 } finally { 984 getFileSystem().finishAtomicAction(); 985 } 986 987 return fo; 988 } 989 990 999 public FileObject createData(String name, String ext) 1000 throws IOException { 1001 MultiFileObject fo; 1002 1003 try { 1004 getFileSystem().beginAtomicAction(); 1005 1006 synchronized (this) { 1007 MultiFileSystem fs = getMultiFileSystem(); 1008 1009 if (fs.isReadOnly()) { 1010 FSException.io("EXC_FSisRO", fs.getDisplayName()); } 1012 1013 if (isReadOnly()) { 1014 FSException.io("EXC_FisRO", name, fs.getDisplayName()); } 1016 1017 String n = "".equals(ext) ? name : (name + EXT_SEP + ext); 1019 if (!isFolder()) { 1020 FSException.io("EXC_FoNotFolder", n, getPath(), fs.getDisplayName()); } 1022 1023 if (this.getFileObject(name, ext) != null) { 1024 FSException.io("EXC_DataAlreadyExist", n, fs.getDisplayName()); } 1026 1027 String fullName = getPath() + PATH_SEP + n; 1028 1029 FileSystem simple = fs.createWritableOn(fullName); 1030 1031 FileUtil.createData(root(simple), fullName); 1033 1034 getMultiFileSystem().unmaskFileOnAll(simple, fullName); 1036 1037 1038 refresh(n, null, true, false); 1040 1041 fo = getMultiChild(n); 1042 1043 if (fo == null) { 1044 throw new FileStateInvalidException( 1046 FileSystem.getString("EXC_ApplicationCreateError", getPath(), n) 1047 ); 1048 } 1049 1050 if (hasListeners()) { 1051 fileCreated0(new FileEvent(this, fo), true); 1052 } 1053 } 1054 } finally { 1055 getFileSystem().finishAtomicAction(); 1056 } 1057 1058 return fo; 1059 } 1060 1061 1072 public void rename(FileLock lock, String name, String ext) 1073 throws IOException { 1074 MultiFileSystem fs = getMultiFileSystem(); 1075 1076 if (parent == null) { 1077 FSException.io("EXC_CannotRenameRoot", fs.getDisplayName()); } 1079 1080 try { 1081 getFileSystem().beginAtomicAction(); 1082 1083 synchronized (parent) { 1084 MfLock l = testLock(lock); 1086 1087 String newFullName = parent.getPath() + PATH_SEP + name; 1088 1089 if (isData()) { 1090 newFullName += (EXT_SEP + ext); 1091 } 1092 1093 String oldFullName = getPath(); 1094 1095 if (isReadOnly()) { 1096 FSException.io("EXC_CannotRename", getPath(), getMultiFileSystem().getDisplayName(), newFullName); } 1098 1099 if (getFileSystem().isReadOnly()) { 1100 FSException.io("EXC_FSisRO", getMultiFileSystem().getDisplayName()); } 1102 1103 String on = getName(); 1104 String oe = getExt(); 1105 1106 FileSystem single = fs.createWritableOnForRename(oldFullName, newFullName); 1108 1109 if (single == leader.getFileSystem()) { 1110 leader.rename(l.findLock(leader), name, ext); 1113 getMultiFileSystem().unmaskFileOnAll(single, newFullName); 1114 copyContent(this, leader); 1115 } else { 1116 FileObject previousLeader = leader; 1119 1120 if (isData()) { 1121 FileObject folder = FileUtil.createFolder(root(single), getParent().getPath()); 1123 leader = leader.copy(folder, name, ext); 1124 copyAttrs(this, leader); 1125 } else { 1126 FileObject fo = FileUtil.createFolder(root(single), newFullName); 1128 copyContent(this, fo); 1129 1130 leader = fo; 1131 this.name = name; update(); 1133 } 1134 1135 l.changeLocks(previousLeader, leader); 1138 } 1139 1140 if (getMultiFileSystem().delegates(oldFullName).hasMoreElements()) { 1141 getMultiFileSystem().maskFile(single, oldFullName); 1144 updateFoldersLock(getParent()); 1145 } 1146 1147 if (isData()) { 1148 name = name + EXT_SEP + ext; 1149 } 1150 1151 String oldName = this.name; 1152 this.name = name; 1153 1154 1160 1161 1162 parent.refresh(name, oldName); 1163 1164 if (hasAtLeastOneListeners()) { 1166 fileRenamed0(new FileRenameEvent(this, on, oe)); 1167 } 1168 } 1169 } finally { 1170 getFileSystem().finishAtomicAction(); 1171 } 1172 } 1173 1174 1180 void handleDelete(FileLock lock) throws IOException { 1181 if (parent == null) { 1182 FSException.io("EXC_CannotDeleteRoot", getMultiFileSystem().getDisplayName() ); 1184 } 1185 1186 MultiFileSystem fs = getMultiFileSystem(); 1187 1188 try { 1189 getFileSystem().beginAtomicAction(); 1190 1191 synchronized (parent) { 1192 String fullName = getPath(); 1193 FileSystem single = fs.createWritableOn(fullName); 1194 1195 if (needsMask(lock, true)) { 1196 getMultiFileSystem().maskFile(single, fullName); 1197 updateFoldersLock(getParent()); 1198 } 1199 1200 String n = name; 1201 validFlag = false; 1202 1203 1204 parent.refresh(null, n, true, false); 1206 1207 if (hasAtLeastOneListeners()) { 1208 fileDeleted0(new FileEvent(this)); 1209 } 1210 } 1211 } finally { 1212 getFileSystem().finishAtomicAction(); 1213 } 1214 } 1215 1216 1220 1229 public FileObject copy(FileObject target, String name, String ext) 1230 throws IOException { 1231 return leader.copy(target, name, ext); 1232 } 1233 1234 1244 public FileObject move(FileLock lock, FileObject target, String name, String ext) 1245 throws IOException { 1246 MultiFileSystem fs = getMultiFileSystem(); 1247 1248 try { 1249 fs.beginAtomicAction(); 1250 1251 if (parent == null) { 1252 FSException.io("EXC_CannotDeleteRoot", fs.getDisplayName() ); 1254 } 1255 1256 MfLock lck = testLock(lock); 1257 FileLock l = lck.findLock(leader); 1258 1259 FileSystem simple = fs.createWritableOn(getPath()); 1260 1261 if (fs.isReadOnly()) { 1262 FSException.io("EXC_FSisRO", fs.getDisplayName()); } 1264 1265 if ((l == null) && (leader.getFileSystem() != simple)) { 1266 leader = writable(); 1267 l = lck.findLock(leader); 1268 } 1269 1270 if (needsMask(lock, false)) { 1271 getMultiFileSystem().maskFile(simple, getPath()); 1272 updateFoldersLock(getParent()); 1273 } 1274 1275 return leader.move(l, target, name, ext); 1276 } finally { 1277 fs.finishAtomicAction(); 1278 } 1279 } 1280 1281 1283 public final void refresh(boolean expected) { 1284 if (!isInitialized() && isFolder()) { 1285 return; 1286 } 1287 1288 Enumeration <FileObject> en = delegates(); 1289 1290 while (en.hasMoreElements()) { 1291 FileObject fo = en.nextElement(); 1292 fo.refresh(expected); 1293 } 1294 1295 super.refresh(expected); 1296 } 1297 1298 1302 1308 public void fileFolderCreated(FileEvent fe) { 1309 1312 updateAll(); 1313 } 1314 1315 1321 public void fileDataCreated(FileEvent fe) { 1322 refreshAfterEvent(fe); 1323 } 1324 1325 1328 public void fileChanged(FileEvent fe) { 1329 FileObject changedFile = this; 1330 1331 if (fe.getSource().equals(leader) && hasAtLeastOneListeners() && !fe.firedFrom(markAtomicAction)) { 1332 1333 if (!fe.getFile().equals(fe.getSource())) { 1334 changedFile = getFileObject(fe.getFile().getName(), fe.getFile().getExt()); 1335 } 1336 1337 1339 1341 if (changedFile != null) { 1342 fileChanged1(new FileEvent(this, changedFile, fe.getTime())); 1343 } 1344 } 1345 } 1346 1347 1350 public void fileDeleted(FileEvent fe) { 1351 if (fe.getFile().isFolder()) { 1352 updateAll(); 1353 } else { 1354 refreshAfterEvent(fe); 1355 } 1356 } 1357 1358 1362 public void fileRenamed(FileRenameEvent fe) { 1363 updateAll(); 1364 } 1365 1366 1370 public void fileAttributeChanged(FileAttributeEvent fe) { 1371 if (!hasAtLeastOneListeners() || (leader == null)) { 1377 return; 1378 } 1379 1380 1382 if (!fe.getFile().equals(leader) && (fe.getName() != null) && (leader.getAttribute(fe.getName()) != null)) { 1383 return; 1384 } 1385 1386 1388 if ( 1389 !fe.getFile().equals(leader) && (fe.getNewValue() != null) && (fe.getName() != null) && 1390 !fe.getNewValue().equals(getAttribute(fe.getName())) 1391 ) { 1392 return; 1393 } 1394 1395 fileAttributeChanged0(new FileAttributeEvent(this, fe.getName(), fe.getOldValue(), fe.getNewValue())); 1396 } 1397 1398 1403 private static void copyContent(FileObject source, FileObject target) 1404 throws IOException { 1405 FileObject[] srcArr = source.getChildren(); 1406 1407 copyAttrs(source, target); 1409 for (int i = 0; i < srcArr.length; i++) { 1410 FileObject child = srcArr[i]; 1411 1412 if (MultiFileSystem.isMaskFile(child)) { 1413 continue; 1414 } 1415 1416 if (target.getFileObject(child.getName(), child.getExt()) == null) { 1417 if (child.isData()) { 1418 FileObject fo = FileUtil.copyFile(child, target, child.getName(), child.getExt()); 1419 1420 if (fo != null) { 1421 copyAttrs(child, fo); 1422 } 1423 } else { 1424 FileObject targetChild = target.createFolder(child.getName()); 1425 copyContent(child, targetChild); 1426 } 1427 } 1428 } 1429 } 1430 1431 1436 private static void copyAttrs(FileObject source, FileObject target) { 1437 Enumeration <String > en = source.getAttributes(); 1438 1439 while (en.hasMoreElements()) { 1440 String key = en.nextElement(); 1441 Object value = source.getAttribute(key); 1442 1443 try { 1444 target.setAttribute(key, value); 1445 } catch (IOException ie) { 1446 } 1447 } 1448 } 1449 1450 1457 private boolean needsMask(FileLock lock, boolean deleteDelegates) 1458 throws IOException { 1459 MfLock lck = testLock(lock); 1460 Enumeration <FileObject> e = getMultiFileSystem().delegates(getPath()); 1461 boolean needsMask = false; 1462 1463 while (e.hasMoreElements()) { 1464 FileObject fo = e.nextElement(); 1465 FileLock lockForFo = lck.findLock(fo); 1466 1467 if (lockForFo == null) { 1468 needsMask = true; 1470 } else { 1471 if (deleteDelegates) { 1472 fo.delete(lockForFo); 1473 } 1474 } 1475 } 1476 1477 return needsMask; 1478 } 1479 1480 1486 private FileObject root(FileSystem fs) { 1487 return getMultiFileSystem().findResourceOn(fs, ""); } 1489 1490 final FileObject getLeader() { 1491 return leader; 1492 } 1493 1494 1498 private static final class VoidValue implements Externalizable { 1499 private static final long serialVersionUID = -2743645909916238684L; 1501 int level; 1502 1503 VoidValue(int level) { 1504 this.level = level; 1505 } 1506 1507 public VoidValue() { 1508 } 1509 1510 public String toString() { 1511 return "org.openide.filesystems.MultiFileObject.VoidValue#" + level; } 1513 1514 public void writeExternal(ObjectOutput out) throws IOException { 1515 out.writeInt(level); 1516 } 1517 1518 public void readExternal(ObjectInput in) throws IOException , ClassNotFoundException { 1519 level = in.readInt(); 1520 } 1521 } 1522 1523 1525 private class MfLock extends FileLock { 1526 1527 private Map <FileObject, FileLock> map = new HashMap <FileObject, FileLock>(11); 1528 1529 1535 public MfLock(FileObject leader, Enumeration <FileObject> delegates, Set systems) 1536 throws IOException { 1537 while (delegates.hasMoreElements()) { 1538 FileObject fo = delegates.nextElement(); 1539 1540 if (systems.contains(fo.getFileSystem())) { 1541 FileLock l = fo.lock(); 1542 map.put(fo, l); 1543 } 1544 } 1545 1546 1559 } 1560 1561 1565 public FileLock findLock(FileObject fo) { 1566 return map.get(fo); 1567 } 1568 1569 1573 public void addLock(FileObject fo) throws IOException { 1574 map.put(fo, fo.lock()); 1575 } 1576 1577 1580 public void changeLocks(FileObject old, FileObject n) 1581 throws IOException { 1582 FileLock l = map.remove(old); 1583 1584 if (l != null) { 1585 l.releaseLock(); 1586 } 1587 1588 addLock(n); 1589 } 1590 1591 public void releaseLock() { 1592 if (this.isValid()) { 1593 super.releaseLock(); 1594 releaseLockForDelegates(); 1595 1596 if (getCurrentMfLock() == this) { 1597 MultiFileObject.this.lock = null; 1599 } 1600 } 1601 } 1602 1603 private FileLock getCurrentMfLock() { 1604 FileLock currentLock = null; 1605 ; 1606 1607 if (lock != null) { 1608 currentLock = (FileLock) lock.get(); 1609 } 1610 1611 return currentLock; 1612 } 1613 1614 private void releaseLockForDelegates() { 1615 Iterator it = map.values().iterator(); 1616 1617 while (it.hasNext()) { 1618 FileLock l = (FileLock) it.next(); 1619 l.releaseLock(); 1620 } 1621 1622 map.clear(); 1623 } 1624 1625 public String toString() { 1627 return super.toString() + " for " + MultiFileObject.this + " valid=" + isValid(); } 1629 } 1630 } 1632 | Popular Tags |