diff --git a/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java b/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java index fc35e56c78b2..a6a940e401cc 100644 --- a/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java +++ b/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java @@ -23,6 +23,8 @@ import com.intellij.openapi.actionSystem.DataKey; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileChooser.FileChooserDescriptor; +import com.intellij.openapi.fileTypes.FileTypeManager; +import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.projectRoots.*; import com.intellij.openapi.roots.AnnotationOrderRootType; @@ -62,8 +64,40 @@ public class JavaSdkImpl extends JavaSdk { private static final String JAVA_VERSION_PREFIX = "java version "; private static final String OPENJDK_VERSION_PREFIX = "openjdk version "; - public JavaSdkImpl() { + public JavaSdkImpl(final VirtualFileManager fileManager, final FileTypeManager fileTypeManager) { super("JavaSDK"); + + fileManager.addVirtualFileListener(new VirtualFileAdapter() { + + public void fileDeleted(@NotNull VirtualFileEvent event) { + updateCache(event); + } + + @Override + public void contentsChanged(@NotNull VirtualFileEvent event) { + updateCache(event); + } + + @Override + public void fileCreated(@NotNull VirtualFileEvent event) { + updateCache(event); + } + + private void updateCache(VirtualFileEvent event) { + final VirtualFile file = event.getFile(); + if (FileTypes.ARCHIVE.equals(fileTypeManager.getFileTypeByFileName(event.getFileName()))) { + final String filePath = file.getPath(); + synchronized (myCachedVersionStrings) { + for (String sdkHome : myCachedVersionStrings.keySet()) { + if (FileUtil.isAncestor(sdkHome, filePath, false)) { + myCachedVersionStrings.remove(sdkHome); + break; + } + } + } + } + } + }); } @Override @@ -428,7 +462,7 @@ public class JavaSdkImpl extends JavaSdk { modificator.addRoot(root, annoType); } - private final Map myCachedVersionStrings = new HashMap(); + private final Map myCachedVersionStrings = Collections.synchronizedMap(new HashMap()); @Override public final String getVersionString(String sdkHome) { diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkTableImpl.java b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkTableImpl.java index 0b7e0bc449c4..28a074a7743a 100644 --- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkTableImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkTableImpl.java @@ -26,8 +26,16 @@ import com.intellij.openapi.projectRoots.*; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; -import com.intellij.openapi.vfs.*; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VfsUtil; +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.VFileEvent; +import com.intellij.util.containers.SmartHashSet; import com.intellij.util.messages.MessageBus; +import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.messages.impl.MessageListenerList; import org.jdom.Element; import org.jetbrains.annotations.NonNls; @@ -35,10 +43,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; @State( name = "ProjectJdkTable", @@ -60,38 +65,102 @@ public class ProjectJdkTableImpl extends ProjectJdkTable implements ExportableCo myMessageBus = ApplicationManager.getApplication().getMessageBus(); myListenerList = new MessageListenerList(myMessageBus, JDK_TABLE_TOPIC); // support external changes to jdk libraries (Endorsed Standards Override) - VirtualFileManager.getInstance().addVirtualFileListener(new VirtualFileAdapter() { + final MessageBusConnection connection = ApplicationManager.getApplication().getMessageBus().connect(); + connection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() { private FileTypeManager myFileTypeManager = FileTypeManager.getInstance(); - @Override - public void fileCreated(@NotNull VirtualFileEvent event) { - updateJdks(event.getFile()); + public void before(@NotNull List events) { } - private void updateJdks(VirtualFile file) { - if (file.isDirectory() || - // avoid calling getFileType() because it will try to detect file type from content for unknown/text file types - !FileTypes.ARCHIVE.equals(myFileTypeManager.getFileTypeByFileName(file.getName()))) { - // consider only archive files that may contain libraries - return; - } - for (Sdk sdk : mySdks) { - final SdkType sdkType = (SdkType)sdk.getSdkType(); - if (!(sdkType instanceof JavaSdkType)) { - continue; + public void after(@NotNull List events) { + if (!events.isEmpty()) { + final Set affected = new SmartHashSet(); + for (VFileEvent event : events) { + addAffectedJavaSdk(event, affected); } - final VirtualFile home = sdk.getHomeDirectory(); - if (home == null) { - continue; - } - if (VfsUtilCore.isAncestor(home, file, true)) { - sdkType.setupSdkPaths(sdk); - // no need to iterate further assuming the file cannot be under the home of several SDKs - break; + if (!affected.isEmpty()) { + for (Sdk sdk : affected) { + ((SdkType)sdk.getSdkType()).setupSdkPaths(sdk); + } } } } + + private void addAffectedJavaSdk(VFileEvent event, Set affected) { + final VirtualFile file = event.getFile(); + String fileName = null; + if (file != null && file.isValid()) { + if (file.isDirectory()) { + return; + } + fileName = file.getName(); + } + final String eventPath = event.getPath(); + if (fileName == null) { + fileName = VfsUtil.extractFileName(eventPath); + } + if (fileName != null) { + // avoid calling getFileType() because it will try to detect file type from content for unknown/text file types + // consider only archive files that may contain libraries + if (!FileTypes.ARCHIVE.equals(myFileTypeManager.getFileTypeByFileName(fileName))) { + return; + } + } + + for (Sdk sdk : mySdks) { + if (sdk.getSdkType() instanceof JavaSdkType && !affected.contains(sdk)) { + final String homePath = sdk.getHomePath(); + if (!StringUtil.isEmpty(homePath) && FileUtil.isAncestor(homePath, eventPath, true)) { + affected.add(sdk); + // no need to iterate further assuming the file cannot be under the home of several SDKs + break; + } + } + } + } + }); + //VirtualFileManager.getInstance().addVirtualFileListener(new VirtualFileAdapter() { + // private FileTypeManager myFileTypeManager = FileTypeManager.getInstance(); + // + // public void fileDeleted(@NotNull VirtualFileEvent event) { + // updateJdks(event.getFile()); + // } + // + // @Override + // public void contentsChanged(@NotNull VirtualFileEvent event) { + // updateJdks(event.getFile()); + // } + // + // @Override + // public void fileCreated(@NotNull VirtualFileEvent event) { + // updateJdks(event.getFile()); + // } + // + // private void updateJdks(VirtualFile file) { + // if (file.isDirectory() || + // // avoid calling getFileType() because it will try to detect file type from content for unknown/text file types + // !FileTypes.ARCHIVE.equals(myFileTypeManager.getFileTypeByFileName(file.getName()))) { + // // consider only archive files that may contain libraries + // return; + // } + // for (Sdk sdk : mySdks) { + // final SdkType sdkType = (SdkType)sdk.getSdkType(); + // if (!(sdkType instanceof JavaSdkType)) { + // continue; + // } + // final VirtualFile home = sdk.getHomeDirectory(); + // if (home == null) { + // continue; + // } + // if (VfsUtilCore.isAncestor(home, file, true)) { + // sdkType.setupSdkPaths(sdk); + // // no need to iterate further assuming the file cannot be under the home of several SDKs + // break; + // } + // } + // } + //}); } @Override diff --git a/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkImpl.java index 2f8f22913b9a..e47c19e27829 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkImpl.java @@ -389,7 +389,12 @@ public class ProjectJdkImpl extends UserDataHolderBase implements JDOMExternaliz } public void update() { - myRootContainer.update(); + try { + myRootContainer.update(); + } + finally { + resetVersionString(); + } } @Override