diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenDistributionsCache.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenDistributionsCache.java index 72b651e6e601..ddd7518520aa 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenDistributionsCache.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenDistributionsCache.java @@ -63,10 +63,11 @@ public class MavenDistributionsCache { } public @NotNull String getVmOptions(@Nullable String workingDirectory) { - if (!useWrapper() || workingDirectory == null) { - return MavenWorkspaceSettingsComponent.getInstance(myProject).getSettings().importingSettings.getVmOptionsForImporter(); + String vmOptions = MavenWorkspaceSettingsComponent.getInstance(myProject).getSettings().getImportingSettings().getVmOptionsForImporter(); + if (workingDirectory == null || !StringUtil.isEmptyOrSpaces(vmOptions)) { + return vmOptions; } - + String multiModuleDir = myWorkingDirToMultimoduleMap.computeIfAbsent(workingDirectory, this::resolveMultimoduleDirectory); return myVmSettingsMap.computeIfAbsent(multiModuleDir, this::readVmOptions); } @@ -74,17 +75,17 @@ public class MavenDistributionsCache { private @NotNull String readVmOptions(@NotNull String multiModuleDir) { MavenWorkspaceSettings settings = MavenWorkspaceSettingsComponent.getInstance(myProject).getSettings(); VirtualFile baseDir = LocalFileSystem.getInstance().findFileByPath(multiModuleDir); - if (baseDir == null) return settings.importingSettings.getVmOptionsForImporter(); + if (baseDir == null) return settings.getImportingSettings().getVmOptionsForImporter(); VirtualFile mvn = baseDir.findChild(".mvn"); - if (mvn == null) return settings.importingSettings.getVmOptionsForImporter(); + if (mvn == null) return settings.getImportingSettings().getVmOptionsForImporter(); VirtualFile jdkOpts = mvn.findChild("jvm.config"); - if (jdkOpts == null) return settings.importingSettings.getVmOptionsForImporter(); + if (jdkOpts == null) return settings.getImportingSettings().getVmOptionsForImporter(); try { return new String(jdkOpts.contentsToByteArray(true), jdkOpts.getCharset()); } catch (IOException e) { MavenLog.LOG.warn(e); - return settings.importingSettings.getVmOptionsForImporter(); + return settings.getImportingSettings().getVmOptionsForImporter(); } } @@ -165,7 +166,7 @@ public class MavenDistributionsCache { .map(p -> p.getDirectory()) .filter(rpDirectory -> FileUtil.isAncestor(rpDirectory, workingDirectory, false)) .findFirst() - .orElse(workingDirectory)); + .orElse(calculateMultimoduleDirUpToFileTree(workingDirectory))); } private @NotNull String calculateMultimoduleDirUpToFileTree(String directory) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenServerConnector.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenServerConnector.java index af95313bf679..f1c8f9470f78 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenServerConnector.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenServerConnector.java @@ -12,7 +12,7 @@ import org.jetbrains.idea.maven.model.MavenModel; import java.io.File; import java.rmi.RemoteException; -import java.util.Collection; +import java.util.*; public abstract class MavenServerConnector implements @NotNull Disposable { public static final Logger LOG = Logger.getInstance(MavenServerConnector.class); @@ -21,7 +21,7 @@ public abstract class MavenServerConnector implements @NotNull Disposable { protected final MavenServerManager myManager; protected @NotNull final MavenDistribution myDistribution; protected final Sdk myJdk; - protected final String myMultimoduleDirectory; + protected final Set myMultimoduleDirectories; protected final String myVmOptions; @@ -36,7 +36,12 @@ public abstract class MavenServerConnector implements @NotNull Disposable { myDistribution = mavenDistribution; myVmOptions = vmOptions; myJdk = jdk; - myMultimoduleDirectory = multimoduleDirectory; + myMultimoduleDirectories = new LinkedHashSet<>(); + myMultimoduleDirectories.add(multimoduleDirectory); + } + + boolean addMultimoduleDir(String multimoduleDirectory) { + return myMultimoduleDirectories.add(multimoduleDirectory); } abstract boolean isNew(); @@ -132,7 +137,7 @@ public abstract class MavenServerConnector implements @NotNull Disposable { return myProject; } - public String getMultimoduleDirectory() { - return myMultimoduleDirectory; + public List getMultimoduleDirectories() { + return new ArrayList<>(myMultimoduleDirectories); } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenServerConnectorImpl.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenServerConnectorImpl.java index 52c4695b4f59..b9d12420613e 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenServerConnectorImpl.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenServerConnectorImpl.java @@ -235,7 +235,8 @@ public class MavenServerConnectorImpl extends MavenServerConnector { @Override public void run() { ProgressIndicator indicator = new EmptyProgressIndicator(); - MavenLog.LOG.info("Connecting maven connector in " + myMultimoduleDirectory); + String dirForLogs = myMultimoduleDirectories.iterator().next(); + MavenLog.LOG.info("Connecting maven connector in " + dirForLogs); try { if (myDebugPort != null) { //noinspection UseOfSystemOutOrSystemErr @@ -253,10 +254,10 @@ public class MavenServerConnectorImpl extends MavenServerConnector { server.set(myLogger, myDownloadListener, MavenRemoteObjectWrapper.ourToken); myServerPromise.setResult(server); - MavenLog.LOG.info("Connector in " + myMultimoduleDirectory + " has been connected"); + MavenLog.LOG.info("Connector in " + dirForLogs + " has been connected"); } catch (Throwable e) { - MavenLog.LOG.warn("Cannot connect connector in " + myMultimoduleDirectory, e); + MavenLog.LOG.warn("Cannot connect connector in " + dirForLogs, e); myServerPromise.setError(e); } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenServerManager.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenServerManager.java index 28dbd47efb22..6891eacec3a7 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenServerManager.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenServerManager.java @@ -62,9 +62,11 @@ public final class MavenServerManager implements Disposable { } public Collection getAllConnectors() { + Set set = Collections.newSetFromMap(new IdentityHashMap<>()); synchronized (myMultimoduleDirToConnectorMap) { - return new ArrayList<>(myMultimoduleDirToConnectorMap.values()); + set.addAll(myMultimoduleDirToConnectorMap.values()); } + return set; } public void cleanUp(MavenServerConnector connector) { @@ -126,28 +128,60 @@ public final class MavenServerManager implements Disposable { MavenWorkspaceSettings settings = MavenWorkspaceSettingsComponent.getInstance(project).getSettings(); Sdk jdk = getJdk(project, settings); - MavenServerConnector connector; - synchronized (myMultimoduleDirToConnectorMap) { - connector = myMultimoduleDirToConnectorMap.computeIfAbsent(multimoduleDirectory, dir -> registerNewConnector(project, jdk, multimoduleDirectory)); - } + MavenServerConnector connector = doGetOrCreateConnector(project, multimoduleDirectory, jdk); if(connector.isNew()) { connector.connect(); } else { - if(!compatibleParameters(project, connector, jdk, multimoduleDirectory)) { + if (!compatibleParameters(project, connector, jdk, multimoduleDirectory)) { MavenLog.LOG.info("Maven connector in " + multimoduleDirectory + " is incompatible, restarting"); connector.shutdown(false); - synchronized (myMultimoduleDirToConnectorMap) { - connector = myMultimoduleDirToConnectorMap.computeIfAbsent(multimoduleDirectory, dir -> registerNewConnector(project, jdk, multimoduleDirectory)); - } + connector = this.doGetOrCreateConnector(project, multimoduleDirectory, jdk); connector.connect(); } } return connector; } - private MavenServerConnector registerNewConnector(Project project, - Sdk jdk, - String multimoduleDirectory) { + private MavenServerConnector doGetOrCreateConnector(@NotNull Project project, + @NotNull String multimoduleDirectory, + @NotNull Sdk jdk) { + MavenServerConnector connector; + synchronized (myMultimoduleDirToConnectorMap) { + connector = myMultimoduleDirToConnectorMap.get(multimoduleDirectory); + if (connector != null) return connector; + connector = findCompatibleConnector(project, jdk, multimoduleDirectory); + if (connector != null) { + MavenLog.LOG.info("use existing connector for " + multimoduleDirectory + ":::" + connector.getMultimoduleDirectories()); + connector.addMultimoduleDir(multimoduleDirectory); + } + else { + connector = registerNewConnector(project, jdk, multimoduleDirectory); + } + myMultimoduleDirToConnectorMap.put(multimoduleDirectory, connector); + } + + return connector; + } + + private @Nullable MavenServerConnector findCompatibleConnector(@NotNull Project project, + @NotNull Sdk jdk, + @NotNull String multimoduleDirectory) { + MavenDistribution distribution = MavenDistributionsCache.getInstance(project).getMavenDistribution(multimoduleDirectory); + String vmOptions = MavenDistributionsCache.getInstance(project).getVmOptions(multimoduleDirectory); + for (Map.Entry entry : myMultimoduleDirToConnectorMap.entrySet()) { + if (!entry.getValue().getProject().equals(project)) continue; + if (Registry.is("maven.server.per.idea.project")) return entry.getValue(); + if (entry.getValue().isCompatibleWith(jdk, vmOptions, distribution)) { + return entry.getValue(); + } + } + + return null; + } + + private @NotNull MavenServerConnector registerNewConnector(Project project, + Sdk jdk, + String multimoduleDirectory) { MavenDistribution distribution = MavenDistributionsCache.getInstance(project).getMavenDistribution(multimoduleDirectory); String vmOptions = MavenDistributionsCache.getInstance(project).getVmOptions(multimoduleDirectory); Integer debugPort = getDebugPort(project); @@ -210,7 +244,7 @@ public final class MavenServerManager implements Disposable { MavenServerConnector connector, Sdk jdk, String multimoduleDirectory) { - + if (Registry.is("maven.server.per.idea.project")) return true; MavenDistributionsCache cache = MavenDistributionsCache.getInstance(project); MavenDistribution distribution = cache.getMavenDistribution(multimoduleDirectory); String vmOptions = cache.getVmOptions(multimoduleDirectory); @@ -436,8 +470,11 @@ public final class MavenServerManager implements Disposable { protected MavenServerIndexer create() throws RemoteException { MavenServerConnector connector; synchronized (myMultimoduleDirToConnectorMap) { - connector = ContainerUtil.find(myMultimoduleDirToConnectorMap.values(), c -> FileUtil - .isAncestor(finalPath, c.getMultimoduleDirectory(), false)); + connector = ContainerUtil.find(myMultimoduleDirToConnectorMap.values(), c -> ContainerUtil.find( + c.myMultimoduleDirectories, + mDir -> FileUtil + .isAncestor(finalPath, mDir, false)) != null + ); } if (connector != null) { return connector.createIndexer(); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/ui/ConnectorTable.kt b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/ui/ConnectorTable.kt index 9396827ca35d..6c807b5d7be6 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/ui/ConnectorTable.kt +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/ui/ConnectorTable.kt @@ -49,7 +49,7 @@ class ConnectorTable : ListTableWithButtons() { val project = TableColumn(MavenConfigurableBundle.message("connector.ui.project")) { it.project.name } val jdk = TableColumn(MavenConfigurableBundle.message("connector.ui.jdk")) { it.jdk.name } val vmopts = TableColumn(MavenConfigurableBundle.message("connector.ui.vmOptions")) { it.vmOptions } - val dir = TableColumn(MavenConfigurableBundle.message("connector.ui.dir")) { it.multimoduleDirectory } + val dir = TableColumn(MavenConfigurableBundle.message("connector.ui.dir")) { it.multimoduleDirectories.joinToString(separator = ",") } val maven = TableColumn( MavenConfigurableBundle.message("connector.ui.maven")) { "${it.mavenDistribution.version} ${it.mavenDistribution.mavenHome}" } val state = TableColumn( diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/ui/ShowMavenConnectorsAction.kt b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/ui/ShowMavenConnectorsAction.kt index dbfca23d25f9..a9f52c3f4e45 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/ui/ShowMavenConnectorsAction.kt +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/ui/ShowMavenConnectorsAction.kt @@ -3,9 +3,10 @@ package org.jetbrains.idea.maven.server.ui import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.DumbAwareAction import org.jetbrains.idea.maven.statistics.MavenActionsUsagesCollector -class ShowMavenConnectorsAction : AnAction() { +class ShowMavenConnectorsAction : DumbAwareAction() { override fun actionPerformed(e: AnActionEvent) { MavenActionsUsagesCollector.trigger(e.project, MavenActionsUsagesCollector.ActionID.ShowMavenConnectors) MavenConnectorList().show() diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenUtil.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenUtil.java index 24f13bf3363a..c551789d5138 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenUtil.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenUtil.java @@ -275,11 +275,17 @@ public class MavenUtil { VirtualFile child = dir.findChild(".mvn"); if (child != null && child.isDirectory()) { + if (MavenLog.LOG.isDebugEnabled()) { + MavenLog.LOG.debug("found .mvn in " + child); + } baseDir = dir; break; } } while ((dir = dir.getParent()) != null); + if (MavenLog.LOG.isDebugEnabled()) { + MavenLog.LOG.debug("return " + baseDir + " as baseDir"); + } return baseDir; } diff --git a/plugins/maven/src/main/resources/META-INF/plugin.xml b/plugins/maven/src/main/resources/META-INF/plugin.xml index e7ba3d1603f1..863857f68bb6 100644 --- a/plugins/maven/src/main/resources/META-INF/plugin.xml +++ b/plugins/maven/src/main/resources/META-INF/plugin.xml @@ -253,8 +253,11 @@ + + + description="Always reset maven dependencies and folders"/> diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/MavenImportingConnectorsTest.kt b/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/MavenImportingConnectorsTest.kt new file mode 100644 index 000000000000..919a638cd388 --- /dev/null +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/MavenImportingConnectorsTest.kt @@ -0,0 +1,144 @@ +// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.idea.maven.importing + +import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.util.registry.Registry +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.idea.maven.MavenImportingTestCase +import org.jetbrains.idea.maven.server.MavenServerManager +import org.jetbrains.idea.maven.wizards.MavenOpenProjectProvider +import java.io.File + +class MavenImportingConnectorsTest : MavenImportingTestCase() { + protected lateinit var myAnotherProjectRoot: VirtualFile + + @Throws(Exception::class) + override fun setUpInWriteAction() { + super.setUpInWriteAction() + val projectDir = File(myDir, "anotherProject") + projectDir.mkdirs() + myAnotherProjectRoot = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(projectDir)!! + } + + fun testShouldNotCreateNewConnectorForNewProject() { + createProjectPom("test" + + "project1" + + "1" + + "pom" + + "" + + "m1" + + " ") + createModulePom("m1", "test" + + "m1" + + "1") + importProject() + assertModules("project1", "m1") + val p2Root = createPomFile(myAnotherProjectRoot, "test" + + "project2" + + "1" + + "pom" + + "" + + "m2" + + " ") + createModulePom("../anotherProject/m2", "test" + + "m2" + + "2") + MavenOpenProjectProvider().linkToExistingProject(p2Root, myProject) + assertModules("project1", "m1", "project2", "m2") + assertEquals(1, MavenServerManager.getInstance().allConnectors.size); + + assertUnorderedElementsAreEqual( + MavenServerManager.getInstance().allConnectors.first().multimoduleDirectories.map { + FileUtil.getRelativePath(myDir, File(it)) + }, + listOf("project", "anotherProject") + ) + } + + fun testShouldCreateNewConnectorForNewProjectIfJvmConfigPresents() { + createProjectPom("test" + + "project1" + + "1" + + "pom" + + "" + + "m1" + + " ") + createModulePom("m1", "test" + + "m1" + + "1") + importProject() + assertModules("project1", "m1") + val p2Root = createPomFile(myAnotherProjectRoot, "test" + + "project2" + + "1" + + "pom" + + "" + + "m2" + + " ") + createModulePom("../anotherProject/m2", "test" + + "m2" + + "2") + + createProjectSubFile("../anotherProject/.mvn/jvm.config", "-Dsomething=blablabla") + MavenOpenProjectProvider().linkToExistingProject(p2Root, myProject) + assertModules("project1", "m1", "project2", "m2") + + assertEquals(2, MavenServerManager.getInstance().allConnectors.size); + + assertUnorderedElementsAreEqual( + MavenServerManager.getInstance().allConnectors.map { + FileUtil.getRelativePath(myDir, File(it.multimoduleDirectories.first())) + }, + listOf("project", "anotherProject") + ) + } + + fun testShouldNotCreateNewConnectorForNewProjectIfJvmConfigPresentsAndRegistrySet() { + createProjectPom("test" + + "project1" + + "1" + + "pom" + + "" + + "m1" + + " ") + createModulePom("m1", "test" + + "m1" + + "1") + importProject() + assertModules("project1", "m1") + val p2Root = createPomFile(myAnotherProjectRoot, "test" + + "project2" + + "1" + + "pom" + + "" + + "m2" + + " ") + createModulePom("../anotherProject/m2", "test" + + "m2" + + "2") + + createProjectSubFile("../anotherProject/.mvn/jvm.config", "-Dsomething=blablabla") + val value = Registry.`is`("maven.server.per.idea.project") + try { + Registry.get("maven.server.per.idea.project").setValue(true); + MavenOpenProjectProvider().linkToExistingProject(p2Root, myProject) + assertModules("project1", "m1", "project2", "m2") + + assertEquals(1, MavenServerManager.getInstance().allConnectors.size); + + assertUnorderedElementsAreEqual( + MavenServerManager.getInstance().allConnectors.first().multimoduleDirectories.map { + FileUtil.getRelativePath(myDir, File(it)) + }, + listOf("project", "anotherProject") + ) + } + finally { + Registry.get("maven.server.per.idea.project").setValue(value) + } + + } + + +} \ No newline at end of file