From da6630875fd5c2ac1f4112a0f40d7bd6558b9822 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Tue, 17 Jan 2012 14:12:19 +0100 Subject: [PATCH] hotswap: scan using java.io.File instead of VirtualFile --- .../intellij/debugger/impl/HotSwapFile.java | 6 +- .../debugger/impl/HotSwapManager.java | 118 +++++++----------- .../debugger/impl/ReloadClassesWorker.java | 23 +--- 3 files changed, 53 insertions(+), 94 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/HotSwapFile.java b/java/debugger/impl/src/com/intellij/debugger/impl/HotSwapFile.java index 07b6862f03de..db0a0fbba311 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/HotSwapFile.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/HotSwapFile.java @@ -15,7 +15,7 @@ */ package com.intellij.debugger.impl; -import com.intellij.openapi.vfs.VirtualFile; +import java.io.File; /** * User: lex @@ -23,9 +23,9 @@ import com.intellij.openapi.vfs.VirtualFile; * Time: 2:23:38 PM */ public class HotSwapFile { - VirtualFile file; + final File file; - public HotSwapFile(VirtualFile file) { + public HotSwapFile(File file) { this.file = file; } } diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/HotSwapManager.java b/java/debugger/impl/src/com/intellij/debugger/impl/HotSwapManager.java index c70fff4e34b7..da688db25bd5 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/HotSwapManager.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/HotSwapManager.java @@ -20,24 +20,21 @@ import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.engine.DebuggerManagerThreadImpl; import com.intellij.debugger.engine.events.DebuggerCommandImpl; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.compiler.ex.CompilerPathsEx; import com.intellij.openapi.components.AbstractProjectComponent; -import com.intellij.openapi.fileTypes.FileTypeManager; -import com.intellij.openapi.fileTypes.FileTypes; -import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.OrderEnumerator; -import com.intellij.openapi.util.Computable; 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.JarFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.newvfs.RefreshQueue; import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NotNull; -import java.util.*; +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; public class HotSwapManager extends AbstractProjectComponent { private final Map myTimeStamps = new HashMap(); @@ -70,56 +67,54 @@ public class HotSwapManager extends AbstractProjectComponent { myTimeStamps.put(session, Long.valueOf(tStamp)); } - public HashMap getModifiedClasses(final DebuggerSession session, final HotSwapProgress progress) { + public Map getModifiedClasses(final DebuggerSession session, final HotSwapProgress progress) { DebuggerManagerThreadImpl.assertIsManagerThread(); - final long timeStamp = getTimeStamp(session); - - final HashMap modifiedClasses = new HashMap(); + final List outputRoots = new ArrayList(); ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { - final List allClasses = OrderEnumerator.orderEntries(myProject).withoutSdk().getPathsList().getRootDirs(); - - final VirtualFile[] allDirs = VfsUtil.toVirtualFileArray(allClasses); - final FileTypeManager fileTypeManager = FileTypeManager.getInstance(); - CompilerPathsEx.visitFiles(allDirs, new CompilerPathsEx.FileVisitor() { - - protected void acceptDirectory(final VirtualFile file, final String fileRoot, final String filePath) { - if (progress.isCancelled()) { - return; - } - progress.setText(DebuggerBundle.message("progress.hotswap.scanning.path", filePath)); - if(file.getFileSystem() instanceof JarFileSystem && FileTypes.ARCHIVE.equals(file.getFileType())) { - if(file.getTimeStamp() > timeStamp) { - super.acceptDirectory(file, fileRoot, filePath); - } - } - else { - super.acceptDirectory(file, fileRoot, filePath); - } - } - - protected void acceptFile(VirtualFile file, String fileRoot, String filePath) { - if (progress.isCancelled()) { - return; - } - if (file.getTimeStamp() > timeStamp && StdFileTypes.CLASS.equals(file.getFileType())) { - //noinspection HardCodedStringLiteral - if (SystemInfo.isFileSystemCaseSensitive? filePath.endsWith(CLASS_EXTENSION) : StringUtil.endsWithIgnoreCase(filePath, CLASS_EXTENSION)) { - progress.setText(DebuggerBundle.message("progress.hotswap.scanning.path", filePath)); - //noinspection HardCodedStringLiteral - final String qualifiedName = filePath.substring(fileRoot.length() + 1, filePath.length() - CLASS_EXTENSION.length()).replace('/', '.'); - modifiedClasses.put(qualifiedName, new HotSwapFile(file)); - } - } - } - }); + final List allClasses = OrderEnumerator.orderEntries(myProject).withoutSdk().withoutLibraries().getPathsList().getRootDirs(); + for (VirtualFile dir : VfsUtil.toVirtualFileArray(allClasses)) { + outputRoots.add(new File(dir.getPath())); + } } }); + final long timeStamp = getTimeStamp(session); + final Map modifiedClasses = new HashMap(); + for (File root : outputRoots) { + final String rootPath = FileUtil.toCanonicalPath(root.getPath()); + collectModifiedClasses(root, rootPath, rootPath + "/", modifiedClasses, progress, timeStamp); + } + return modifiedClasses; } + private static boolean collectModifiedClasses(File file, String filePath, String rootPath, Map container, HotSwapProgress progress, long timeStamp) { + if (progress.isCancelled()) { + return false; + } + final File[] files = file.listFiles(); + if (files != null) { + for (File child : files) { + if (!collectModifiedClasses(child, filePath + "/" + child.getName(), rootPath, container, progress, timeStamp)) { + return false; + } + } + } + else { // not a dir + if (SystemInfo.isFileSystemCaseSensitive? StringUtil.endsWith(filePath, CLASS_EXTENSION) : StringUtil.endsWithIgnoreCase(filePath, CLASS_EXTENSION)) { + if (file.lastModified() > timeStamp) { + progress.setText(DebuggerBundle.message("progress.hotswap.scanning.path", filePath)); + //noinspection HardCodedStringLiteral + final String qualifiedName = filePath.substring(rootPath.length(), filePath.length() - CLASS_EXTENSION.length()).replace('/', '.'); + container.put(qualifiedName, new HotSwapFile(file)); + } + } + } + return true; + } + public static HotSwapManager getInstance(Project project) { return project.getComponent(HotSwapManager.class); } @@ -141,15 +136,12 @@ public class HotSwapManager extends AbstractProjectComponent { } }); - final Set projectsToRefresh = new HashSet(); for (final DebuggerSession debuggerSession : sessions) { if (debuggerSession.isAttached()) { - projectsToRefresh.add(debuggerSession.getProject()); scanClassesCommand.addCommand(debuggerSession.getProcess(), new DebuggerCommandImpl() { protected void action() throws Exception { swapProgress.setDebuggerSession(debuggerSession); - HashMap sessionClasses = - getInstance(swapProgress.getProject()).getModifiedClasses(debuggerSession, swapProgress); + final Map sessionClasses = getInstance(swapProgress.getProject()).getModifiedClasses(debuggerSession, swapProgress); if (!sessionClasses.isEmpty()) { modifiedClasses.put(debuggerSession, sessionClasses); } @@ -159,27 +151,7 @@ public class HotSwapManager extends AbstractProjectComponent { } swapProgress.setTitle(DebuggerBundle.message("progress.hotswap.scanning.classes")); - if (!scanClassesCommand.isEmpty()) { - // have to refresh dirs first: - final Collection roots = ApplicationManager.getApplication().runReadAction(new Computable>() { - public Collection compute() { - final Set result = new HashSet(); - for (Project project : projectsToRefresh) { - for (VirtualFile file : OrderEnumerator.orderEntries(project).withoutSdk().getPathsList().getRootDirs()) { - if (!file.getFileSystem().isReadOnly()) { - result.add(file); - } - } - } - return result; - } - }); - - if (!roots.isEmpty()) { - RefreshQueue.getInstance().refresh(false, true, null, roots.toArray(new VirtualFile[roots.size()])); - } - scanClassesCommand.run(); - } + scanClassesCommand.run(); return swapProgress.isCancelled() ? new HashMap>() : modifiedClasses; } diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/ReloadClassesWorker.java b/java/debugger/impl/src/com/intellij/debugger/impl/ReloadClassesWorker.java index 9f8d82d29833..106df8fee7c3 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/ReloadClassesWorker.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/ReloadClassesWorker.java @@ -21,11 +21,10 @@ import com.intellij.debugger.engine.DebugProcessImpl; import com.intellij.debugger.engine.events.DebuggerCommandImpl; import com.intellij.debugger.jdi.VirtualMachineProxyImpl; import com.intellij.debugger.ui.breakpoints.BreakpointManager; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.StringBuilderSpinAllocator; import com.intellij.util.ui.MessageCategory; import com.sun.jdi.ReferenceType; @@ -116,34 +115,22 @@ class ReloadClassesWorker { try { final Map redefineMap = new HashMap(); int processedClassesCount = 0; - final IOException[] _ex = new IOException[] {null}; for (final String qualifiedName : modifiedClasses.keySet()) { processedClassesCount++; if (qualifiedName != null) { myProgress.setText(qualifiedName); myProgress.setFraction(processedClassesCount / (double)modifiedClasses.size()); } - _ex[0] = null; final HotSwapFile fileDescr = modifiedClasses.get(qualifiedName); - final byte[] buffer = ApplicationManager.getApplication().runReadAction(new Computable() { - public byte[] compute() { - try { - return fileDescr.file.contentsToByteArray(); - } - catch (IOException e) { - _ex[0] = e; - return null; - } - } - }); - if (buffer != null) { + try { + final byte[] buffer = FileUtil.loadFileBytes(fileDescr.file); final List classes = virtualMachineProxy.classesByName(qualifiedName); for (final ReferenceType reference : classes) { redefineMap.put(reference, buffer); } } - else { - reportProblem(qualifiedName, _ex[0]); + catch (IOException e) { + reportProblem(qualifiedName, e); } if (redefineMap.size() >= CLASSES_CHUNK_SIZE) { // reload this portion of clasess and clear the map to free memory