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 e7435953af9b..bfb69296dc62 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 @@ -403,10 +403,10 @@ public class JavaSdkImpl extends JavaSdk { } }; - rootContainer.startChange(); - addClasses(jdkHomeFile, sdkModificator, isJre); - addSources(jdkHomeFile, sdkModificator); - rootContainer.finishChange(); + rootContainer.changeRoots(() -> { + addClasses(jdkHomeFile, sdkModificator, isJre); + addSources(jdkHomeFile, sdkModificator); + }); ProjectJdkImpl jdk = new ProjectJdkImpl(jdkName, this, homePath, jdkName) { @Override @@ -503,7 +503,7 @@ public class JavaSdkImpl extends JavaSdk { } }; - ProjectJdkImpl.copyRoots(rootContainer, jdk); + jdk.copyRootsFrom(rootContainer); return jdk; } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerManagerImpl.java index b0cd6c1d4f49..a2fec0e2cb13 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerManagerImpl.java @@ -326,7 +326,8 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp try { for (VirtualFilePointerImpl pointer : pointers) { if (!myStoredPointers.contains(pointer)) { - pointer.throwDisposalError("Virtual pointer hasn't been disposed: "+pointer); + pointer.throwDisposalError("Virtual pointer '" + pointer + + "' hasn't been disposed: "+pointer.getStackTrace()); } } } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/ex/ProjectRootContainer.java b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/ex/ProjectRootContainer.java index 7e8e3b249926..d3486d45c5ac 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/ex/ProjectRootContainer.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/ex/ProjectRootContainer.java @@ -33,8 +33,8 @@ public interface ProjectRootContainer { VirtualFile[] getRootFiles(@NotNull OrderRootType type); @NotNull ProjectRoot[] getRoots(@NotNull OrderRootType type); - void startChange(); - void finishChange(); + // must execute modifications inside this method only + void changeRoots(@NotNull Runnable change); @NotNull ProjectRoot addRoot(@NotNull VirtualFile virtualFile, @NotNull OrderRootType type); 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 1023a3a7fe9d..93322a0c0d72 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 @@ -24,11 +24,11 @@ import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.roots.RootProvider; import com.intellij.openapi.roots.impl.RootProviderBaseImpl; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.openapi.vfs.StandardFileSystems; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; import org.jdom.Element; @@ -55,10 +55,6 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi @NonNls public static final String ELEMENT_TYPE = "type"; @NonNls private static final String ELEMENT_VERSION = "version"; @NonNls private static final String ELEMENT_ROOTS = "roots"; - @NonNls private static final String ELEMENT_ROOT = "root"; - @NonNls private static final String ELEMENT_PROPERTY = "property"; - @NonNls private static final String VALUE_JDKHOME = "jdkHome"; - @NonNls private static final String ATTRIBUTE_FILE = "file"; @NonNls private static final String ELEMENT_HOMEPATH = "homePath"; @NonNls private static final String ELEMENT_ADDITIONAL = "additional"; @@ -134,7 +130,7 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi readExternal(element, null); } - public void readExternal(@NotNull Element element, @Nullable ProjectJdkTable projectJdkTable) { + public void readExternal(@NotNull Element element, @Nullable ProjectJdkTable projectJdkTable) throws InvalidDataException { myName = element.getChild(ELEMENT_NAME).getAttributeValue(ATTRIBUTE_VALUE); final Element typeChild = element.getChild(ELEMENT_TYPE); final String sdkTypeName = typeChild != null ? typeChild.getAttributeValue(ATTRIBUTE_VALUE) : null; @@ -155,25 +151,14 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi myVersionDefined = false; } - if (element.getAttribute(ELEMENT_VERSION) == null || !"2".equals(element.getAttributeValue(ELEMENT_VERSION))) { - myRootContainer.startChange(); - myRootContainer.readOldVersion(element.getChild(ELEMENT_ROOTS)); - final List children = element.getChild(ELEMENT_ROOTS).getChildren(ELEMENT_ROOT); - for (final Object aChildren : children) { - Element root = (Element)aChildren; - for (final Object o : root.getChildren(ELEMENT_PROPERTY)) { - Element prop = (Element)o; - if (ELEMENT_TYPE.equals(prop.getAttributeValue(ELEMENT_NAME)) && VALUE_JDKHOME.equals(prop.getAttributeValue(ATTRIBUTE_VALUE))) { - myHomePath = VirtualFileManager.extractPath(root.getAttributeValue(ATTRIBUTE_FILE)); - } - } + myRootContainer.changeRoots(() -> { + String versionValue = element.getAttributeValue(ELEMENT_VERSION, ""); + if (versionValue.isEmpty() || !"2".equals(versionValue)) { + throw new InvalidDataException("Too old version is not supported: " + versionValue); } - myRootContainer.finishChange(); - } - else { myHomePath = element.getChild(ELEMENT_HOMEPATH).getAttributeValue(ATTRIBUTE_VALUE); myRootContainer.readExternal(element.getChild(ELEMENT_ROOTS)); - } + }); final Element additional = element.getChild(ELEMENT_ADDITIONAL); if (additional != null) { @@ -244,26 +229,18 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi return myRootProvider; } - void copyTo(ProjectJdkImpl dest) { + void copyTo(@NotNull ProjectJdkImpl dest) { final String name = getName(); dest.setName(name); dest.setHomePath(getHomePath()); dest.myVersionDefined = myVersionDefined; dest.myVersionString = myVersionString; dest.setSdkAdditionalData(getSdkAdditionalData()); - copyRoots(myRootContainer, dest); + dest.copyRootsFrom(myRootContainer); } - static void copyRoots(@NotNull ProjectRootContainerImpl rootContainer, @NotNull ProjectJdkImpl dest) { - dest.myRootContainer.startChange(); - dest.myRootContainer.removeAllRoots(); - for (OrderRootType rootType : OrderRootType.getAllTypes()) { - final ProjectRoot[] newRoots = rootContainer.getRoots(rootType); - for (ProjectRoot newRoot : newRoots) { - dest.myRootContainer.addRoot(newRoot, rootType); - } - } - dest.myRootContainer.finishChange(); + void copyRootsFrom(@NotNull ProjectRootContainerImpl rootContainer) { + myRootContainer.copyRootsFrom(rootContainer); } private class MyRootProvider extends RootProviderBaseImpl implements ProjectRootListener { @@ -329,7 +306,7 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi @Override public void commitChanges() { LOG.assertTrue(isWritable()); - myRootContainer.finishChange(); + copyTo(myOrigin); myOrigin = null; } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectRootContainerImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectRootContainerImpl.java index 49aee3a25902..d3e90b052727 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectRootContainerImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectRootContainerImpl.java @@ -28,7 +28,7 @@ import com.intellij.openapi.util.JDOMExternalizable; import com.intellij.openapi.vfs.*; import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.HashMap; +import gnu.trove.THashMap; import org.jdom.Element; import org.jetbrains.annotations.NotNull; @@ -40,9 +40,8 @@ import java.util.Map; */ public class ProjectRootContainerImpl implements JDOMExternalizable, ProjectRootContainer { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.projectRoots.impl.ProjectRootContainerImpl"); - private final Map myRoots = new HashMap<>(); - - private Map myFiles = new HashMap<>(); + private final Map myRoots = new THashMap<>(); + private final Map myCachedFiles = new THashMap<>(); private boolean myInsideChange; private final List myListeners = ContainerUtil.createLockFreeCopyOnWriteList(); @@ -54,14 +53,14 @@ public class ProjectRootContainerImpl implements JDOMExternalizable, ProjectRoot for (OrderRootType rootType : OrderRootType.getAllTypes()) { myRoots.put(rootType, new CompositeProjectRoot()); - myFiles.put(rootType, VirtualFile.EMPTY_ARRAY); + myCachedFiles.put(rootType, VirtualFile.EMPTY_ARRAY); } } @Override @NotNull public VirtualFile[] getRootFiles(@NotNull OrderRootType type) { - return ObjectUtils.chooseNotNull(myFiles.get(type), VirtualFile.EMPTY_ARRAY); + return ObjectUtils.chooseNotNull(myCachedFiles.get(type), VirtualFile.EMPTY_ARRAY); } @Override @@ -70,29 +69,46 @@ public class ProjectRootContainerImpl implements JDOMExternalizable, ProjectRoot return myRoots.get(type).getProjectRoots(); } - @Override - public void startChange() { - LOG.assertTrue(!myInsideChange); + void startChange() { + myInsideChange = true; // argh!! has to have this abomination just because of horrible Sdk.getSdkModificator()/commitChanges() are separated + } - myInsideChange = true; + private void assertNotInsideChange() { + if (myInsideChange) throw new IllegalStateException(); + } + private void assertInsideChange() { + if (!myInsideChange) throw new IllegalStateException(); } @Override - public void finishChange() { - LOG.assertTrue(myInsideChange); - Map oldRoots = new HashMap<>(myFiles); + public void changeRoots(@NotNull Runnable change) { + assertNotInsideChange(); + myInsideChange = true; + Map oldRoots = new THashMap<>(myCachedFiles); - boolean changes = false; + try { + change.run(); + } + finally { + myInsideChange = false; + + if (cacheFiles(oldRoots)) { + fireRootsChanged(); + } + } + } + + + private boolean cacheFiles(@NotNull Map oldRoots) { + myCachedFiles.clear(); + + boolean changed = false; for (OrderRootType orderRootType : OrderRootType.getAllTypes()) { final VirtualFile[] roots = myRoots.get(orderRootType).getVirtualFiles(); - changes = changes || !Comparing.equal(roots, oldRoots.get(orderRootType)); - myFiles.put(orderRootType, roots); + changed |= !Comparing.equal(roots, oldRoots.get(orderRootType)); + myCachedFiles.put(orderRootType, roots); } - if (changes) { - fireRootsChanged(); - } - - myInsideChange = false; + return changed; } void addProjectRootContainerListener(@NotNull ProjectRootListener listener) { @@ -109,41 +125,40 @@ public class ProjectRootContainerImpl implements JDOMExternalizable, ProjectRoot } } - @Override public void removeRoot(@NotNull ProjectRoot root, @NotNull OrderRootType type) { - LOG.assertTrue(myInsideChange); + assertInsideChange(); myRoots.get(type).remove(root); } @Override @NotNull public ProjectRoot addRoot(@NotNull VirtualFile virtualFile, @NotNull OrderRootType type) { - LOG.assertTrue(myInsideChange); + assertInsideChange(); return myRoots.get(type).add(virtualFile); } @Override public void addRoot(@NotNull ProjectRoot root, @NotNull OrderRootType type) { - LOG.assertTrue(myInsideChange); + assertInsideChange(); myRoots.get(type).add(root); } @Override public void removeAllRoots(@NotNull OrderRootType type) { - LOG.assertTrue(myInsideChange); + assertInsideChange(); myRoots.get(type).clear(); } @Override public void removeRoot(@NotNull VirtualFile root, @NotNull OrderRootType type) { - LOG.assertTrue(myInsideChange); + assertInsideChange(); myRoots.get(type).remove(root); } @Override public void removeAllRoots() { - LOG.assertTrue(myInsideChange); + assertInsideChange(); for (CompositeProjectRoot myRoot : myRoots.values()) { myRoot.clear(); } @@ -151,7 +166,7 @@ public class ProjectRootContainerImpl implements JDOMExternalizable, ProjectRoot @Override public void update() { - LOG.assertTrue(myInsideChange); + assertInsideChange(); for (CompositeProjectRoot myRoot : myRoots.values()) { myRoot.update(); } @@ -159,19 +174,18 @@ public class ProjectRootContainerImpl implements JDOMExternalizable, ProjectRoot @Override public void readExternal(Element element) { + assertInsideChange(); for (PersistentOrderRootType type : OrderRootType.getAllPersistentTypes()) { read(element, type); } ApplicationManager.getApplication().runReadAction(() -> { - myFiles = new HashMap<>(); - for (Map.Entry entry : myRoots.entrySet()) { - CompositeProjectRoot root = entry.getValue(); + myRoots.values().forEach(root -> { if (myNoCopyJars) { setNoCopyJars(root); } - myFiles.put(entry.getKey(), root.getVirtualFiles()); - } + }); + cacheFiles(new THashMap<>(myCachedFiles)); }); for (OrderRootType type : OrderRootType.getAllTypes()) { @@ -192,6 +206,18 @@ public class ProjectRootContainerImpl implements JDOMExternalizable, ProjectRoot } } + void copyRootsFrom(@NotNull ProjectRootContainerImpl rootContainer) { + changeRoots(() -> { + removeAllRoots(); + for (OrderRootType rootType : OrderRootType.getAllTypes()) { + final ProjectRoot[] newRoots = rootContainer.getRoots(rootType); + for (ProjectRoot newRoot : newRoots) { + addRoot(newRoot, rootType); + } + } + }); + } + private static void setNoCopyJars(ProjectRoot root) { if (root instanceof SimpleProjectRoot) { String url = ((SimpleProjectRoot)root).getUrl(); @@ -220,7 +246,9 @@ public class ProjectRootContainerImpl implements JDOMExternalizable, ProjectRoot } List children = child.getChildren(); - LOG.assertTrue(children.size() == 1); + if (children.size() != 1) { + LOG.error(children); + } CompositeProjectRoot root = (CompositeProjectRoot)ProjectRootUtil.read(children.get(0)); myRoots.put(type, root); } @@ -234,33 +262,4 @@ public class ProjectRootContainerImpl implements JDOMExternalizable, ProjectRoot e.addContent(root); } } - - @SuppressWarnings("HardCodedStringLiteral") - void readOldVersion(Element child) { - for (Element root : child.getChildren("root")) { - String url = root.getAttributeValue("file"); - SimpleProjectRoot projectRoot = new SimpleProjectRoot(url); - String type = root.getChild("property").getAttributeValue("value"); - - for (PersistentOrderRootType rootType : OrderRootType.getAllPersistentTypes()) { - if (type.equals(rootType.getOldSdkRootName())) { - addRoot(projectRoot, rootType); - break; - } - } - } - - myFiles = new HashMap<>(); - for (Map.Entry entry : myRoots.entrySet()) { - myFiles.put(entry.getKey(), entry.getValue().getVirtualFiles()); - } - for (OrderRootType type : OrderRootType.getAllTypes()) { - final VirtualFile[] oldRoots = VirtualFile.EMPTY_ARRAY; - final VirtualFile[] newRoots = getRootFiles(type); - if (!Comparing.equal(oldRoots, newRoots)) { - fireRootsChanged(); - break; - } - } - } } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/SimpleProjectRoot.java b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/SimpleProjectRoot.java index bce60fb5224f..f3cc5910a4dd 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/SimpleProjectRoot.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/SimpleProjectRoot.java @@ -18,10 +18,8 @@ package com.intellij.openapi.projectRoots.impl; import com.intellij.openapi.projectRoots.ex.ProjectRoot; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; -import com.intellij.util.PathUtil; import com.intellij.util.io.URLUtil; import org.jdom.Element; import org.jetbrains.annotations.NonNls; @@ -81,7 +79,7 @@ public class SimpleProjectRoot implements ProjectRoot { @Override @NotNull public String[] getUrls() { - return new String[]{myUrl}; + return new String[]{getUrl()}; } @Override @@ -120,21 +118,7 @@ public class SimpleProjectRoot implements ProjectRoot { @NotNull private static String readUrl(Element element) { - String url = element.getAttributeValue(ATTRIBUTE_URL); - return migrateJdkAnnotationsToCommunityForDevIdea(url); - } - - // hack to migrate internal IDEA jdk annos dir from IDEA_PROJECT_HOME/jdkAnnotations to IDEA_PROJECT_HOME/community/java/jdkAnnotations - @NotNull - private static String migrateJdkAnnotationsToCommunityForDevIdea(@NotNull String url) { - File root = new File(VfsUtilCore.urlToPath(url) + "/.."); - boolean isOldJdkAnnotations = new File(root, "community/java/jdkAnnotations").exists() - && new File(root, "idea.iml").exists() - && new File(root, "testData").exists(); - if (isOldJdkAnnotations) { - return VfsUtilCore.pathToUrl(PathUtil.getCanonicalPath(VfsUtilCore.urlToPath(url + "/../community/java/jdkAnnotations"))); - } - return url; + return element.getAttributeValue(ATTRIBUTE_URL); } public void writeExternal(Element element) { @@ -142,6 +126,6 @@ public class SimpleProjectRoot implements ProjectRoot { initialize(); } - element.setAttribute(ATTRIBUTE_URL, myUrl); + element.setAttribute(ATTRIBUTE_URL, getUrl()); } }