4 package com
.intellij
.openapi
.vfs
.newvfs
.impl
;
6 import com
.intellij
.openapi
.vfs
.VirtualFile
;
7 import com
.intellij
.openapi
.vfs
.newvfs
.NewVirtualFile
;
8 import com
.intellij
.openapi
.vfs
.newvfs
.NewVirtualFileSystem
;
9 import com
.intellij
.openapi
.vfs
.newvfs
.RefreshQueue
;
10 import com
.intellij
.openapi
.vfs
.newvfs
.events
.VFileCreateEvent
;
11 import com
.intellij
.util
.ArrayUtil
;
12 import com
.intellij
.util
.text
.CaseInsensitiveStringHashingStrategy
;
13 import gnu
.trove
.THashMap
;
14 import gnu
.trove
.THashSet
;
15 import org
.jetbrains
.annotations
.NotNull
;
16 import org
.jetbrains
.annotations
.Nullable
;
18 import java
.io
.IOException
;
19 import java
.io
.InputStream
;
20 import java
.io
.OutputStream
;
23 public class VirtualDirectoryImpl
extends VirtualFileSystemEntry
{
24 private final NewVirtualFileSystem myFS
;
25 private Object myChildren
; // Either HashMap<String, VFile> or VFile[]
27 public VirtualDirectoryImpl(final String name
, final VirtualDirectoryImpl parent
, final NewVirtualFileSystem fs
, final int id
) {
28 super(name
, parent
, id
);
33 public NewVirtualFileSystem
getFileSystem() {
38 private NewVirtualFile
findChild(final String name
, final boolean createIfNotFound
) {
39 if (name
.length() == 0) {
43 final VirtualFile
[] a
= asArray();
45 for (VirtualFile file
: a
) {
46 if (namesEqual(name
, file
.getName())) return (NewVirtualFile
)file
;
49 return createIfNotFound ?
createAndFindChildWithEventFire(name
) : null;
52 final Map
<String
, VirtualFile
> map
;
53 final VirtualFile file
;
59 if (file
== NullVirtualFile
.INSTANCE
) {
60 return createIfNotFound ?
createAndFindChildWithEventFire(name
) : null;
63 if (file
!= null) return (NewVirtualFile
)file
;
65 final NewVirtualFileSystem delegate
= getFileSystem();
66 VirtualFile fake
= new FakeVirtualFile(name
, this);
67 String name1
= delegate
.getCanonicallyCasedName(fake
);
69 int id
= ourPersistence
.getId(this, name1
);
72 VirtualFile alreadyCreated
= map
.get(name1
);
73 if (alreadyCreated
!= null) {
74 if (alreadyCreated
== NullVirtualFile
.INSTANCE
) {
75 return createIfNotFound ?
createAndFindChildWithEventFire(name
) : null;
77 return (NewVirtualFile
)alreadyCreated
;
79 NewVirtualFile child
= createChild(name1
, id
);
80 map
.put(name1
, child
);
86 if (myChildren
instanceof Map
) {
87 ensureAsMap().put(name1
, NullVirtualFile
.INSTANCE
);
94 public VirtualFileSystemEntry
createChild(String name
, int id
) {
95 final NewVirtualFileSystem fs
= getFileSystem();
96 final VirtualFileSystemEntry child
= ourPersistence
.isDirectory(id
) ?
97 new VirtualDirectoryImpl(name
, this, fs
, id
) :
98 new VirtualFileImpl(name
, this, id
);
99 if (fs
.markNewFilesAsDirty()) {
107 private NewVirtualFile
createAndFindChildWithEventFire(final String name
) {
108 final NewVirtualFileSystem delegate
= getFileSystem();
109 VirtualFile fake
= new FakeVirtualFile(name
, this);
110 if (delegate
.exists(fake
)) {
111 final String realName
= delegate
.getCanonicallyCasedName(fake
);
112 VFileCreateEvent event
= new VFileCreateEvent(null, this, realName
, delegate
.isDirectory(fake
), true);
113 RefreshQueue
.getInstance().processSingleEvent(event
);
114 return findChild(realName
);
122 public NewVirtualFile
refreshAndFindChild(final String name
) {
123 return findChild(name
, true);
127 public synchronized NewVirtualFile
findChildIfCached(final String name
) {
128 final VirtualFile
[] a
= asArray();
130 for (VirtualFile file
: a
) {
131 if (namesEqual(name
, file
.getName())) return (NewVirtualFile
)file
;
137 final Map
<String
, VirtualFile
> map
= asMap();
139 final VirtualFile file
= map
.get(name
);
140 return file
instanceof NewVirtualFile ?
(NewVirtualFile
)file
: null;
147 public synchronized Collection
<VirtualFile
> getInDbChildren() {
148 if (myChildren
instanceof VirtualFile
[]) {
149 return Arrays
.asList((VirtualFile
[])myChildren
);
152 if (!ourPersistence
.wereChildrenAccessed(this)) {
153 return Collections
.emptyList();
156 if (ourPersistence
.areChildrenLoaded(this)) {
157 return Arrays
.asList(getChildren());
160 final String
[] names
= ourPersistence
.listPersisted(this);
161 for (String name
: names
) {
162 findChild(name
, false);
165 return ensureAsMap().values();
169 public synchronized VirtualFile
[] getChildren() {
170 if (myChildren
instanceof VirtualFile
[]) {
171 return (VirtualFile
[])myChildren
;
174 final int[] childrenIds
= ourPersistence
.listIds(this);
175 VirtualFile
[] children
;
176 if (childrenIds
.length
== 0) {
177 children
= EMPTY_ARRAY
;
180 children
= new VirtualFile
[childrenIds
.length
];
181 final Map
<String
, VirtualFile
> map
= asMap();
182 for (int i
= 0; i
< children
.length
; i
++) {
183 final int childId
= childrenIds
[i
];
184 final String name
= ourPersistence
.getName(childId
);
185 VirtualFile child
= map
!= null ? map
.get(name
) : null;
187 children
[i
] = child
!= null && child
!= NullVirtualFile
.INSTANCE ? child
: createChild(name
, childId
);
192 myChildren
= children
;
199 public NewVirtualFile
findChild(@NotNull final String name
) {
200 return findChild(name
, false);
204 private synchronized VirtualFile
[] asArray() {
205 if (myChildren
instanceof VirtualFile
[]) return (VirtualFile
[])myChildren
;
210 @SuppressWarnings({"unchecked"})
211 private synchronized Map
<String
, VirtualFile
> asMap() {
212 if (myChildren
instanceof Map
) return (Map
<String
, VirtualFile
>)myChildren
;
217 @SuppressWarnings({"unchecked"})
218 private synchronized Map
<String
, VirtualFile
> ensureAsMap() {
219 assert !(myChildren
instanceof VirtualFile
[]);
221 if (myChildren
== null) {
222 myChildren
= createMap();
225 return (Map
<String
, VirtualFile
>)myChildren
;
228 public synchronized void addChild(VirtualFile file
) {
229 final VirtualFile
[] a
= asArray();
231 myChildren
= ArrayUtil
.append(a
, file
);
234 final Map
<String
, VirtualFile
> m
= ensureAsMap();
235 m
.put(file
.getName(), file
);
239 public synchronized void removeChild(VirtualFile file
) {
240 final VirtualFile
[] a
= asArray();
242 myChildren
= ArrayUtil
.remove(a
, file
);
245 final Map
<String
, VirtualFile
> m
= ensureAsMap();
246 m
.put(file
.getName(), NullVirtualFile
.INSTANCE
);
250 public synchronized boolean allChildrenLoaded() {
251 return myChildren
instanceof VirtualFile
[];
254 public synchronized List
<String
> getSuspicousNames() {
255 final Map
<String
, VirtualFile
> map
= asMap();
256 if (map
== null) return Collections
.emptyList();
258 List
<String
> names
= new ArrayList
<String
>();
259 for (Map
.Entry
<String
, VirtualFile
> entry
: map
.entrySet()) {
260 if (entry
.getValue() == NullVirtualFile
.INSTANCE
) {
261 names
.add(entry
.getKey());
268 public boolean isDirectory() {
273 public synchronized Collection
<VirtualFile
> getCachedChildren() {
274 final Map
<String
, VirtualFile
> map
= asMap();
276 Set
<VirtualFile
> files
= new THashSet
<VirtualFile
>(map
.values());
277 files
.remove(NullVirtualFile
.INSTANCE
);
281 final VirtualFile
[] a
= asArray();
282 if (a
!= null) return Arrays
.asList(a
);
284 return Collections
.emptyList();
287 private boolean namesEqual(final String name1
, final String name2
) {
288 return getFileSystem().isCaseSensitive() ? name1
.equals(name2
) : name1
.equalsIgnoreCase(name2
);
291 private Map
<String
, VirtualFile
> createMap() {
292 return getFileSystem().isCaseSensitive()
293 ?
new THashMap
<String
, VirtualFile
>()
294 : new THashMap
<String
, VirtualFile
>(CaseInsensitiveStringHashingStrategy
.INSTANCE
);
297 public synchronized void cleanupCachedChildren() {
302 public InputStream
getInputStream() throws IOException
{
303 throw new IOException("getInputStream() must not be called against a directory: " + getUrl());
307 public OutputStream
getOutputStream(final Object requestor
, final long newModificationStamp
, final long newTimeStamp
) throws IOException
{
308 throw new IOException("getOutputStream() must not be called against a directory: " + getUrl());