diff --git a/org.eclipse.jdt.ls.core/plugin.xml b/org.eclipse.jdt.ls.core/plugin.xml index 9188d895a8..4de51d6e89 100644 --- a/org.eclipse.jdt.ls.core/plugin.xml +++ b/org.eclipse.jdt.ls.core/plugin.xml @@ -4,6 +4,7 @@ + @@ -115,4 +116,28 @@ order="1500" class="org.eclipse.jdt.ls.core.internal.managers.InvisibleProjectImporter" /> + + + + + + + diff --git a/org.eclipse.jdt.ls.core/schema/org.eclipse.jdt.ls.core.buildSupport.exsd b/org.eclipse.jdt.ls.core/schema/org.eclipse.jdt.ls.core.buildSupport.exsd new file mode 100644 index 0000000000..84c37ea0b9 --- /dev/null +++ b/org.eclipse.jdt.ls.core/schema/org.eclipse.jdt.ls.core.buildSupport.exsd @@ -0,0 +1,101 @@ + + + + + + + + + This extension point represents different kinds of project build supporters for the JDT LS. +Each extension must implement <code>org.eclipse.jdt.ls.core.internal.managers.IBuildSupport</code>. + + + + + + + + + + + + + + + + + a fully qualified identifier of the target extension point + + + + + + + an optional identifier of the extension instance + + + + + + + an optional name of the extension instance + + + + + + + + + + + + A unique identifier that can be used to reference this IBuildSupport. + + + + + + + The class that implements this build support. The class must implement IBuildSupport. + + + + + + + + + + The query order of the build support. Lowest value has the highest priority. + + + + + + + + + + + + + The following is an example of a language server content provider extension: + +<pre> + <extension + id="buildSupport" + point="org.eclipse.jdt.ls.core.buildSupport"> + <buildSupport + id="someBuildSupport" + order="200" + class="com.example.SomeBuildSupport" /> + </extension> +</pre> + + + + + + + diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/DefaultProjectBuildSupport.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/DefaultProjectBuildSupport.java index c3cb493683..1690fa02c2 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/DefaultProjectBuildSupport.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/DefaultProjectBuildSupport.java @@ -13,18 +13,13 @@ package org.eclipse.jdt.ls.core.internal.managers; import org.eclipse.core.resources.IProject; +import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; public class DefaultProjectBuildSupport extends EclipseBuildSupport implements IBuildSupport { - private ProjectsManager projectManager; - - public DefaultProjectBuildSupport(ProjectsManager projectManager) { - this.projectManager = projectManager; - } - @Override public boolean applies(IProject project) { - return projectManager.getDefaultProject().equals(project); + return JavaLanguageServerPlugin.getProjectsManager().getDefaultProject().equals(project); } } diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/GradleBuildSupport.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/GradleBuildSupport.java index c4d15b1341..d6d29791a2 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/GradleBuildSupport.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/GradleBuildSupport.java @@ -14,6 +14,8 @@ import java.io.File; import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; import java.util.Optional; import org.eclipse.buildship.core.BuildConfiguration; @@ -45,6 +47,7 @@ public class GradleBuildSupport implements IBuildSupport { public static final String GRADLE_SUFFIX = ".gradle"; public static final String GRADLE_PROPERTIES = "gradle.properties"; + public static final List WATCH_FILE_PATTERNS = Arrays.asList("**/*.gradle", "**/gradle.properties"); @Override public boolean applies(IProject project) { @@ -131,4 +134,10 @@ public static void saveModels() { public ILaunchConfiguration getLaunchConfiguration(IJavaProject javaProject, String scope) throws CoreException { return new JavaApplicationLaunchConfiguration(javaProject.getProject(), scope, GradleClasspathProvider.ID); } + + @Override + public List getWatchPatterns() { + return WATCH_FILE_PATTERNS; + } + } diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/IBuildSupport.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/IBuildSupport.java index 25491fdbb0..c27f605f97 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/IBuildSupport.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/IBuildSupport.java @@ -12,6 +12,9 @@ *******************************************************************************/ package org.eclipse.jdt.ls.core.internal.managers; +import java.util.Collections; +import java.util.List; + import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; @@ -109,4 +112,8 @@ default ILaunchConfiguration getLaunchConfiguration(IJavaProject javaProject, St return new JavaApplicationLaunchConfiguration(javaProject.getProject(), scope, null); } + default List getWatchPatterns() { + return Collections.emptyList(); + } + } diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/MavenBuildSupport.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/MavenBuildSupport.java index 255fdffaa8..7ab89e7965 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/MavenBuildSupport.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/MavenBuildSupport.java @@ -14,6 +14,7 @@ import java.nio.file.Path; import java.util.Collection; +import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -57,6 +58,7 @@ public class MavenBuildSupport implements IBuildSupport { private static final int MAX_TIME_MILLIS = 3000; + private static final List WATCH_FILE_PATTERNS = Collections.singletonList("**/pom.xml"); private static Cache downloadRequestsCache = CacheBuilder.newBuilder().maximumSize(100).expireAfterWrite(1, TimeUnit.HOURS).build(); private IProjectConfigurationManager configurationManager; @@ -185,4 +187,10 @@ public void discoverSource(IClassFile classFile, IProgressMonitor monitor) throw public ILaunchConfiguration getLaunchConfiguration(IJavaProject javaProject, String scope) throws CoreException { return new JavaApplicationLaunchConfiguration(javaProject.getProject(), scope, MavenRuntimeClasspathProvider.MAVEN_CLASSPATH_PROVIDER); } + + @Override + public List getWatchPatterns() { + return WATCH_FILE_PATTERNS; + } + } diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/StandardProjectsManager.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/StandardProjectsManager.java index af0ccac75d..180c52e866 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/StandardProjectsManager.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/StandardProjectsManager.java @@ -28,8 +28,10 @@ import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.TreeMap; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -42,11 +44,14 @@ import org.eclipse.core.resources.ISaveContext; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.jobs.Job; @@ -55,6 +60,7 @@ import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.ls.core.internal.ActionableNotification; +import org.eclipse.jdt.ls.core.internal.IConstants; import org.eclipse.jdt.ls.core.internal.JDTUtils; import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; import org.eclipse.jdt.ls.core.internal.JobHelpers; @@ -72,14 +78,12 @@ import org.eclipse.lsp4j.WatchKind; public class StandardProjectsManager extends ProjectsManager { + protected static final String BUILD_SUPPORT_EXTENSION_POINT_ID = "buildSupport"; private static final Set watchers = new LinkedHashSet<>(); private PreferenceManager preferenceManager; //@formatter:off private static final List basicWatchers = Arrays.asList( "**/*.java", - "**/pom.xml", - "**/*.gradle", - "**/gradle.properties", "**/.project", "**/.classpath", "**/.settings/*.prefs", @@ -272,8 +276,19 @@ public Optional getBuildSupport(IProject project) { return buildSupports().filter(bs -> bs.applies(project)).findFirst(); } - private Stream buildSupports() { - return Stream.of(new GradleBuildSupport(), new MavenBuildSupport(), new InvisibleProjectBuildSupport(), new DefaultProjectBuildSupport(this), new EclipseBuildSupport()); + protected Stream buildSupports() { + Map supporters = new TreeMap<>(); + IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(IConstants.PLUGIN_ID, BUILD_SUPPORT_EXTENSION_POINT_ID); + IConfigurationElement[] configs = extensionPoint.getConfigurationElements(); + for (IConfigurationElement config : configs) { + try { + Integer order = Integer.valueOf(config.getAttribute("order")); + supporters.put(order, (IBuildSupport) config.createExecutableExtension("class")); //$NON-NLS-1$ + } catch (CoreException e) { + JavaLanguageServerPlugin.logError(config.getAttribute("class") + " implementation was skipped \n" + e.getStatus()); + } + } + return supporters.values().stream(); } @Override @@ -302,6 +317,7 @@ public List registerWatchers() { logInfo(">> registerFeature 'workspace/didChangeWatchedFiles'"); if (preferenceManager.getClientPreferences().isWorkspaceChangeWatchedFilesDynamicRegistered()) { Set patterns = new LinkedHashSet<>(basicWatchers); + buildSupports().forEach(e -> e.getWatchPatterns().forEach(patterns::add)); Set sources = new HashSet<>(); IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); try { diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/StandardProjectManagerTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/StandardProjectManagerTest.java new file mode 100644 index 0000000000..6fca84102a --- /dev/null +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/StandardProjectManagerTest.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2020 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.ls.core.internal.managers; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager; +import org.eclipse.jdt.ls.core.internal.preferences.StandardPreferenceManager; +import org.junit.Test; + +/** + * @author siarhei_leanavets1 + * + */ +public class StandardProjectManagerTest { + + private class StandardProjectsManagerDummy extends StandardProjectsManager { + /** + * @param preferenceManager + */ + public StandardProjectsManagerDummy(PreferenceManager preferenceManager) { + super(preferenceManager); + } + + @Override + public Stream buildSupports() { + return super.buildSupports(); + } + } + + @Test + public void testCheckBuildSupportOrder() { + PreferenceManager preferenceManager = mock(StandardPreferenceManager.class); + StandardProjectsManagerDummy projectsManagerDummy = new StandardProjectsManagerDummy(preferenceManager); + List> expectedList = Arrays.asList(GradleBuildSupport.class, MavenBuildSupport.class, InvisibleProjectBuildSupport.class, DefaultProjectBuildSupport.class, EclipseBuildSupport.class); + List actualList = projectsManagerDummy.buildSupports().collect(Collectors.toList()); + for (int i = 0; i < expectedList.size(); i++) { + assertEquals(expectedList.get(i), actualList.get(i).getClass()); + } + } + +}