1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
package org.jetbrains.builtInWebServer;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.intellij.ProjectTopics;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootAdapter;
import com.intellij.openapi.roots.ModuleRootEvent;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
import com.intellij.openapi.vfs.newvfs.events.VFileContentChangeEvent;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
import com.intellij.util.PairFunction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* Implement {@link WebServerRootsProvider} to add your provider
*/
public class WebServerPathToFileManager {
private static final PairFunction<String, VirtualFile, VirtualFile> RELATIVE_PATH_RESOLVER = new PairFunction<String, VirtualFile, VirtualFile>() {
@Nullable
@Override
public VirtualFile fun(String path, VirtualFile parent) {
return parent.findFileByRelativePath(path);
}
};
private static final PairFunction<String, VirtualFile, VirtualFile> EMPTY_PATH_RESOLVER = new PairFunction<String, VirtualFile, VirtualFile>() {
@Nullable
@Override
public VirtualFile fun(String path, VirtualFile parent) {
return BuiltInWebServer.findIndexFile(parent);
}
};
private final Project project;
final Cache<String, VirtualFile> pathToFileCache = CacheBuilder.newBuilder().maximumSize(512).expireAfterAccess(10, TimeUnit.MINUTES).build();
// time to expire should be greater than pathToFileCache
private final Cache<VirtualFile, PathInfo> fileToRoot = CacheBuilder.newBuilder().maximumSize(512).expireAfterAccess(11, TimeUnit.MINUTES).build();
public static WebServerPathToFileManager getInstance(@NotNull Project project) {
return ServiceManager.getService(project, WebServerPathToFileManager.class);
}
public WebServerPathToFileManager(@NotNull Application application, @NotNull Project project) {
this.project = project;
application.getMessageBus().connect(project).subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener.Adapter() {
@Override
public void after(@NotNull List<? extends VFileEvent> events) {
for (VFileEvent event : events) {
if (event instanceof VFileContentChangeEvent) {
VirtualFile file = ((VFileContentChangeEvent)event).getFile();
for (WebServerRootsProvider rootsProvider : WebServerRootsProvider.EP_NAME.getExtensions()) {
if (rootsProvider.isClearCacheOnFileContentChanged(file)) {
clearCache();
break;
}
}
}
else {
clearCache();
break;
}
}
}
});
project.getMessageBus().connect().subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootAdapter() {
@Override
public void rootsChanged(ModuleRootEvent event) {
clearCache();
}
});
}
private void clearCache() {
pathToFileCache.invalidateAll();
fileToRoot.invalidateAll();
}
@Nullable
public VirtualFile get(@NotNull String path) {
return get(path, true);
}
@Nullable
public VirtualFile get(@NotNull String path, boolean cacheResult) {
VirtualFile result = pathToFileCache.getIfPresent(path);
if (result == null || !result.isValid()) {
result = findByRelativePath(project, path);
if (cacheResult && result != null && result.isValid()) {
pathToFileCache.put(path, result);
}
}
return result;
}
@Nullable
public String getPath(@NotNull VirtualFile file) {
PathInfo pathInfo = getRoot(file);
return pathInfo == null ? null : pathInfo.getPath();
}
@Nullable
public PathInfo getRoot(@NotNull VirtualFile child) {
PathInfo result = fileToRoot.getIfPresent(child);
if (result == null) {
for (WebServerRootsProvider rootsProvider : WebServerRootsProvider.EP_NAME.getExtensions()) {
result = rootsProvider.getRoot(child, project);
if (result != null) {
fileToRoot.put(child, result);
break;
}
}
}
return result;
}
@Nullable
VirtualFile findByRelativePath(@NotNull Project project, @NotNull String path) {
for (WebServerRootsProvider rootsProvider : WebServerRootsProvider.EP_NAME.getExtensions()) {
PathInfo result = rootsProvider.resolve(path, project);
if (result != null) {
fileToRoot.put(result.getChild(), result);
return result.getChild();
}
}
return null;
}
@NotNull
public PairFunction<String, VirtualFile, VirtualFile> getResolver(@NotNull String path) {
return path.isEmpty() ? EMPTY_PATH_RESOLVER : RELATIVE_PATH_RESOLVER;
}
}
|