From a68db0067e78b26fb1a66db867f0bb1f1bed4a6f Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Thu, 11 Dec 2014 17:00:10 +0100 Subject: [PATCH] IDEA-134061 Built-in web server does not serve content from JAR files --- .../roots/impl/libraries/LibraryImpl.java | 9 +- .../DefaultWebServerRootsProvider.java | 176 ++++++++++++++---- .../jetbrains/builtInWebServer/PathInfo.java | 18 +- 3 files changed, 166 insertions(+), 37 deletions(-) diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryImpl.java index 7b5de892d4da..39275de3eb14 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryImpl.java @@ -174,8 +174,13 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi public VirtualFile[] getFiles(@NotNull OrderRootType rootType) { checkDisposed(); - final List expanded = new ArrayList(); - for (VirtualFile file : myRoots.get(rootType).getFiles()) { + VirtualFilePointerContainer container = myRoots.get(rootType); + if (container == null) { + return VirtualFile.EMPTY_ARRAY; + } + + List expanded = new SmartList(); + for (VirtualFile file : container.getFiles()) { if (file.isDirectory()) { if (myJarDirectories.contains(rootType, file.getUrl())) { collectJarFiles(file, expanded, myJarDirectories.isRecursive(rootType, file.getUrl())); diff --git a/xml/impl/src/org/jetbrains/builtInWebServer/DefaultWebServerRootsProvider.java b/xml/impl/src/org/jetbrains/builtInWebServer/DefaultWebServerRootsProvider.java index e1d1b9616e52..a26020f66ef8 100644 --- a/xml/impl/src/org/jetbrains/builtInWebServer/DefaultWebServerRootsProvider.java +++ b/xml/impl/src/org/jetbrains/builtInWebServer/DefaultWebServerRootsProvider.java @@ -20,17 +20,28 @@ import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.JavadocOrderRootType; import com.intellij.openapi.roots.ModuleRootManager; -import com.intellij.openapi.roots.ProjectFileIndex; -import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.roots.OrderEntry; +import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.roots.impl.DirectoryIndex; +import com.intellij.openapi.roots.impl.DirectoryInfo; +import com.intellij.openapi.roots.impl.ModuleLibraryOrderEntryImpl; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.PairFunction; import com.intellij.util.PlatformUtils; +import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; final class DefaultWebServerRootsProvider extends WebServerRootsProvider { + private static OrderRootType[] ORDER_ROOT_TYPES; + @Nullable @Override public PathInfo resolve(@NotNull String path, @NotNull Project project) { @@ -53,9 +64,12 @@ final class DefaultWebServerRootsProvider extends WebServerRootsProvider { resolver = WebServerPathToFileManager.getInstance(project).getResolver(path); ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); - PathInfo result = resolve(path, moduleRootManager.getSourceRoots(), resolver, moduleName); + PathInfo result = findByRelativePath(path, moduleRootManager.getSourceRoots(), resolver, moduleName); if (result == null) { - result = resolve(path, moduleRootManager.getContentRoots(), resolver, moduleName); + result = findByRelativePath(path, moduleRootManager.getContentRoots(), resolver, moduleName); + if (result == null) { + result = findInModuleLibraries(path, module, resolver); + } } if (result != null) { return result; @@ -77,45 +91,140 @@ final class DefaultWebServerRootsProvider extends WebServerRootsProvider { PathInfo result = findByRelativePath(project, path, modules, true, resolver); if (result == null) { // let's find in content roots - return findByRelativePath(project, path, modules, false, resolver); + result = findByRelativePath(project, path, modules, false, resolver); + if (result == null) { + return findInLibraries(project, modules, path, resolver); + } } - else { - return result; + return result; + } + + @Nullable + private static PathInfo findInModuleLibraries(@NotNull String path, @NotNull Module module, @NotNull PairFunction resolver) { + int index = path.indexOf('/'); + if (index <= 0) { + return null; } + + Ref result = Ref.create(); + findInModuleLibraries(resolver, path.substring(0, index), path.substring(index + 1), result, module); + return result.get(); + } + + @Nullable + private static PathInfo findInLibraries(@NotNull Project project, + @NotNull Module[] modules, + @NotNull String path, + @NotNull PairFunction resolver) { + int index = path.indexOf('/'); + if (index < 0) { + return null; + } + + if (ORDER_ROOT_TYPES == null) { + ORDER_ROOT_TYPES = new OrderRootType[]{JavadocOrderRootType.getInstance(), OrderRootType.DOCUMENTATION, OrderRootType.SOURCES, OrderRootType.CLASSES}; + } + + String libraryFileName = path.substring(0, index); + String relativePath = path.substring(index + 1); + AccessToken token = ReadAction.start(); + try { + Ref result = Ref.create(); + for (Module module : modules) { + if (!module.isDisposed()) { + if (findInModuleLibraries(resolver, libraryFileName, relativePath, result, module)) { + return result.get(); + } + } + } + + for (Library library : LibraryTablesRegistrar.getInstance().getLibraryTable(project).getLibraries()) { + PathInfo pathInfo = findInLibrary(libraryFileName, relativePath, library, resolver); + if (pathInfo != null) { + return pathInfo; + } + } + } + finally { + token.finish(); + } + + return null; + } + + private static boolean findInModuleLibraries(@NotNull final PairFunction resolver, + @NotNull final String libraryFileName, + @NotNull final String relativePath, + @NotNull final Ref result, + @NotNull Module module) { + ModuleRootManager.getInstance(module).orderEntries().forEachLibrary(new Processor() { + @Override + public boolean process(Library library) { + result.set(findInLibrary(libraryFileName, relativePath, library, resolver)); + return result.isNull(); + } + }); + return !result.isNull(); + } + + @Nullable + private static PathInfo findInLibrary(@NotNull String libraryFileName, + @NotNull String relativePath, + @NotNull Library library, + @NotNull PairFunction resolver) { + for (OrderRootType rootType : ORDER_ROOT_TYPES) { + for (VirtualFile root : library.getFiles(rootType)) { + if (StringUtil.equalsIgnoreCase(root.getNameSequence(), libraryFileName)) { + VirtualFile file = resolver.fun(relativePath, root); + if (file != null) { + return new PathInfo(file, root, null, true); + } + } + } + } + return null; } @Nullable @Override - public PathInfo getRoot(@NotNull final VirtualFile file, @NotNull Project project) { + public PathInfo getRoot(@NotNull VirtualFile file, @NotNull Project project) { AccessToken token = ReadAction.start(); try { - VirtualFile root; - ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex(); - - VirtualFile notExcludedParent = file; - while (notExcludedParent != null && fileIndex.isExcluded(notExcludedParent)) { - notExcludedParent = notExcludedParent.getParent(); - } - - if (notExcludedParent == null) { + DirectoryIndex directoryIndex = DirectoryIndex.getInstance(project); + DirectoryInfo info = directoryIndex.getInfoForFile(file); + if (!info.isInProject()) { return null; } - if (fileIndex.isInSourceContent(notExcludedParent)) { - root = fileIndex.getSourceRootForFile(notExcludedParent); - } - else if (fileIndex.isInContent(notExcludedParent)) { - root = fileIndex.getContentRootForFile(notExcludedParent); - } - else if (fileIndex.isInLibraryClasses(notExcludedParent)) { - root = fileIndex.getClassRootForFile(notExcludedParent); + VirtualFile root = info.getSourceRoot(); + boolean isLibrary; + if (root == null) { + root = info.getContentRoot(); + if (root == null) { + root = info.getLibraryClassRoot(); + isLibrary = true; + + assert root != null : file.getPresentableUrl(); + } + else { + isLibrary = false; + } } else { - // not in project - return null; + isLibrary = info.isInLibrarySource(); } - assert root != null : file.getPresentableUrl(); - return new PathInfo(file, root, getModuleNameQualifier(project, fileIndex.getModuleForFile(notExcludedParent))); + + Module module = info.getModule(); + if (isLibrary && module == null) { + for (OrderEntry entry : directoryIndex.getOrderEntries(info)) { + if (entry instanceof ModuleLibraryOrderEntryImpl) { + module = entry.getOwnerModule(); + break; + } + } + } + + return new PathInfo(file, root, getModuleNameQualifier(project, module), isLibrary); } finally { token.finish(); @@ -133,11 +242,14 @@ final class DefaultWebServerRootsProvider extends WebServerRootsProvider { } @Nullable - private static PathInfo resolve(@NotNull String path, @NotNull VirtualFile[] roots, @NotNull PairFunction resolver, @Nullable String moduleName) { + private static PathInfo findByRelativePath(@NotNull String path, + @NotNull VirtualFile[] roots, + @NotNull PairFunction resolver, + @Nullable String moduleName) { for (VirtualFile root : roots) { VirtualFile file = resolver.fun(path, root); if (file != null) { - return new PathInfo(file, root, moduleName); + return new PathInfo(file, root, moduleName, false); } } return null; @@ -152,7 +264,7 @@ final class DefaultWebServerRootsProvider extends WebServerRootsProvider { for (Module module : modules) { if (!module.isDisposed()) { ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); - PathInfo result = resolve(path, inSourceRoot ? moduleRootManager.getSourceRoots() : moduleRootManager.getContentRoots(), resolver, null); + PathInfo result = findByRelativePath(path, inSourceRoot ? moduleRootManager.getSourceRoots() : moduleRootManager.getContentRoots(), resolver, null); if (result != null) { result.moduleName = getModuleNameQualifier(project, module); return result; diff --git a/xml/impl/src/org/jetbrains/builtInWebServer/PathInfo.java b/xml/impl/src/org/jetbrains/builtInWebServer/PathInfo.java index b55b16be84b2..8837beaa4957 100644 --- a/xml/impl/src/org/jetbrains/builtInWebServer/PathInfo.java +++ b/xml/impl/src/org/jetbrains/builtInWebServer/PathInfo.java @@ -8,18 +8,21 @@ import org.jetbrains.annotations.Nullable; public class PathInfo { private final VirtualFile child; private final VirtualFile root; + private final boolean isLibrary; + String moduleName; private String computedPath; - public PathInfo(@NotNull VirtualFile child, @NotNull VirtualFile root, @Nullable String moduleName) { + public PathInfo(@NotNull VirtualFile child, @NotNull VirtualFile root, @Nullable String moduleName, boolean isLibrary) { this.child = child; this.root = root; this.moduleName = moduleName; + this.isLibrary = isLibrary; } public PathInfo(@NotNull VirtualFile child, @NotNull VirtualFile root) { - this(child, root, null); + this(child, root, null, false); } @NotNull @@ -40,7 +43,16 @@ public class PathInfo { @NotNull public String getPath() { if (computedPath == null) { - computedPath = (moduleName == null ? "" : moduleName + '/') + VfsUtilCore.getRelativePath(child, root, '/'); + StringBuilder builder = new StringBuilder(); + if (moduleName != null) { + builder.append(moduleName).append('/'); + } + + if (isLibrary) { + builder.append(root.getName()).append('/'); + } + + computedPath = builder.append(VfsUtilCore.getRelativePath(child, root, '/')).toString(); } return computedPath; }