blob: 987fdcd3a139dc0ff8060197168dffd0b6862d02 [file] [log] [blame]
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;
}
}