[java] JRT file system API

This commit is contained in:
Roman Shevchenko
2016-10-21 18:07:30 +02:00
parent 93a48124c3
commit 116065fe63
9 changed files with 101 additions and 88 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@ import com.intellij.lang.LangBundle;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.vfs.impl.jrt.JrtFileSystem;
import com.intellij.openapi.vfs.jrt.JrtFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.presentation.java.ClassPresentationUtil;
@@ -36,7 +36,7 @@ import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.impl.jrt.JrtFileSystem;
import com.intellij.openapi.vfs.jrt.JrtFileSystem;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
@@ -665,12 +665,10 @@ public class JavaSdkImpl extends JavaSdk {
List<VirtualFile> result = ContainerUtil.newArrayList();
VirtualFileManager fileManager = VirtualFileManager.getInstance();
String path = file.getPath();
if (JrtFileSystem.isModularJdk(path)) {
String url = VirtualFileManager.constructUrl(JrtFileSystem.PROTOCOL, FileUtil.toSystemIndependentName(path) + JrtFileSystem.SEPARATOR);
for (String module : JrtFileSystem.listModules(path)) {
ContainerUtil.addIfNotNull(result, fileManager.findFileByUrl(url + module));
}
VirtualFile jrt = fileManager.findFileByUrl(
VirtualFileManager.constructUrl(JrtFileSystem.PROTOCOL, FileUtil.toSystemIndependentName(file.getPath()) + JrtFileSystem.SEPARATOR));
if (jrt != null) {
ContainerUtil.addAll(result, jrt.getChildren());
}
for (File root : JavaSdkUtil.getJdkClassesRoots(file, isJre)) {
@@ -23,18 +23,22 @@ import com.intellij.notification.Notifications;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdk;
import com.intellij.openapi.projectRoots.ProjectJdkTable;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.impl.ArchiveHandler;
import com.intellij.openapi.vfs.newvfs.*;
import com.intellij.openapi.vfs.jrt.JrtFileSystem;
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
import com.intellij.openapi.vfs.newvfs.RefreshQueue;
import com.intellij.openapi.vfs.newvfs.VfsImplUtil;
import com.intellij.openapi.vfs.newvfs.events.VFileContentChangeEvent;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
import com.intellij.util.containers.ContainerUtil;
@@ -42,36 +46,19 @@ import com.intellij.util.messages.MessageBusConnection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.*;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.intellij.util.containers.ContainerUtil.newTroveMap;
public class JrtFileSystem extends ArchiveFileSystem {
public static final String PROTOCOL = StandardFileSystems.JRT_PROTOCOL;
public static final String PROTOCOL_PREFIX = StandardFileSystems.JRT_PROTOCOL_PREFIX;
public static final String SEPARATOR = JarFileSystem.JAR_SEPARATOR;
private static final boolean SUPPORTED =
SystemInfo.isJavaVersionAtLeast("9") || SystemInfo.isJavaVersionAtLeast("1.8") && !SystemInfo.isJavaVersionAtLeast("1.9");
private static final URI ROOT_URI = URI.create("jrt:/");
public class JrtFileSystemImpl extends JrtFileSystem {
private final Map<String, ArchiveHandler> myHandlers = newTroveMap(FileUtil.PATH_HASHING_STRATEGY);
private final AtomicBoolean mySubscribed = new AtomicBoolean(false);
public JrtFileSystem() {
public JrtFileSystemImpl() {
scheduleConfiguredSdkCheck();
}
@@ -213,51 +200,4 @@ public class JrtFileSystem extends ArchiveFileSystem {
protected boolean isCorrectFileType(@NotNull VirtualFile local) {
return isModularJdk(FileUtil.toSystemDependentName(local.getPath()));
}
public static boolean isSupported() {
return SUPPORTED;
}
public static boolean isModularJdk(@NotNull String homePath) {
return new File(homePath, "lib/modules").exists() && new File(homePath, "jrt-fs.jar").isFile();
}
public static boolean isRoot(@NotNull VirtualFile file) {
return file.getParent() == null && file.getFileSystem() instanceof JrtFileSystem;
}
public static boolean isModuleRoot(@NotNull VirtualFile file) {
VirtualFile parent = file.getParent();
return parent != null && isRoot(parent);
}
@NotNull
public static List<String> listModules(@NotNull String path) {
try {
Path root = getFileSystem(path).getPath("/modules");
return Files.list(root).map(p -> p.getFileName().toString()).collect(Collectors.toList());
}
catch (IOException | InvalidPathException e) {
Logger.getInstance(JrtFileSystem.class).warn(path, e);
return Collections.emptyList();
}
}
static FileSystem getFileSystem(String path) throws IOException {
try {
if (SystemInfo.isJavaVersionAtLeast("9")) {
return FileSystems.newFileSystem(ROOT_URI, Collections.singletonMap("java.home", path));
}
else {
File file = new File(path, "jrt-fs.jar");
if (!file.exists()) throw new IOException("Missing provider: " + file);
URL url = file.toURI().toURL();
ClassLoader loader = new URLClassLoader(new URL[]{url}, null);
return FileSystems.newFileSystem(ROOT_URI, Collections.emptyMap(), loader);
}
}
catch (Error e) {
throw new IOException("Error mounting JRT filesystem at " + path, e);
}
}
}
@@ -15,20 +15,27 @@
*/
package com.intellij.openapi.vfs.impl.jrt;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.vfs.impl.ArchiveHandler;
import com.intellij.reference.SoftReference;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collections;
import java.util.Map;
class JrtHandler extends ArchiveHandler {
private static final URI ROOT_URI = URI.create("jrt:/");
private SoftReference<FileSystem> myFileSystem;
public JrtHandler(@NotNull String path) {
@@ -38,8 +45,23 @@ class JrtHandler extends ArchiveHandler {
private synchronized FileSystem getFileSystem() throws IOException {
FileSystem fs = SoftReference.dereference(myFileSystem);
if (fs == null) {
fs = JrtFileSystem.getFileSystem(getFile().getPath());
myFileSystem = new SoftReference<>(fs);
String path = getFile().getPath();
try {
if (SystemInfo.isJavaVersionAtLeast("9")) {
fs = FileSystems.newFileSystem(ROOT_URI, Collections.singletonMap("java.home", path));
}
else {
File file = new File(path, "jrt-fs.jar");
if (!file.exists()) throw new IOException("Missing provider: " + file);
URL url = file.toURI().toURL();
ClassLoader loader = new URLClassLoader(new URL[]{url}, null);
fs = FileSystems.newFileSystem(ROOT_URI, Collections.emptyMap(), loader);
}
myFileSystem = new SoftReference<>(fs);
}
catch (RuntimeException | Error e) {
throw new IOException("Error mounting JRT filesystem at " + path, e);
}
}
return fs;
}
@@ -27,7 +27,7 @@ import com.intellij.openapi.roots.SourceFolder;
import com.intellij.openapi.roots.ui.configuration.SourceRootPresentation;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.impl.jrt.JrtFileSystem;
import com.intellij.openapi.vfs.jrt.JrtFileSystem;
import com.intellij.openapi.vfs.newvfs.ArchiveFileSystem;
import com.intellij.psi.JavaDirectoryService;
import com.intellij.psi.PsiDirectory;